Mercurial > sci
view db.c @ 3:215c0c3b3609
misc: use JSON everywhere (scictl/sciwebd)
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 14 Jun 2021 22:08:24 +0200 |
parents | 5fa3d2f479b2 |
children | 9c4fea43803c |
line wrap: on
line source
#include <sys/queue.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include <sqlite3.h> #include "db.h" #include "log.h" #include "types.h" #include "util.h" #include "sql/init.h" #include "sql/job-add.h" #include "sql/job-todo.h" #include "sql/jobresult-add.h" #include "sql/project-add.h" #include "sql/project-find.h" #include "sql/project-find-id.h" #include "sql/project-list.h" #include "sql/worker-add.h" #include "sql/worker-find.h" #include "sql/worker-find-id.h" #include "sql/worker-list.h" #define CHAR(v) (const char *)(v) static sqlite3 *db; struct str { char *str; SLIST_ENTRY(str) link; }; SLIST_HEAD(strlist, str); static struct strlist * strlist_new(void) { struct strlist *l; l = util_calloc(1, sizeof (*l)); SLIST_INIT(l); return l; } static const char * strlist_add(struct strlist *l, const char *text) { struct str *s; s = util_calloc(1, sizeof (*s)); s->str = util_strdup(text); SLIST_INSERT_HEAD(l, s, link); return s->str; } static void strlist_free(struct strlist *l) { struct str *s, *tmp; SLIST_FOREACH_SAFE(s, l, link, tmp) { free(s->str); free(s); } SLIST_INIT(l); } static inline void convert_project(struct db_ctx *ctx, struct project *project, sqlite3_stmt *stmt) { project->id = sqlite3_column_int(stmt, 0); project->name = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 1))); project->desc = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 2))); project->url = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 3))); project->script = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 4))); } static int insert(const char *sql, const char *fmt, ...) { assert(sql); assert(fmt); sqlite3_stmt *stmt = NULL; va_list ap; if (sqlite3_prepare(db, sql, -1, &stmt, NULL) != SQLITE_OK) return log_warn("db: %s", sqlite3_errmsg(db)), -1; va_start(ap, fmt); for (int index = 1; *fmt; ++fmt) { switch (*fmt) { case 'i': sqlite3_bind_int(stmt, index++, va_arg(ap, int)); break; case 's': sqlite3_bind_text(stmt, index++, va_arg(ap, const char *), -1, SQLITE_STATIC); break; default: break; } } va_end(ap); if (sqlite3_step(stmt) != SQLITE_DONE) { log_warn("db: %s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return -1; } return sqlite3_last_insert_rowid(db); } int db_open(const char *path) { assert(path); if (sqlite3_open(path, &db) != SQLITE_OK) { log_warn("db: open error: %s", sqlite3_errmsg(db)); return -1; } /* Wait for 30 seconds to lock the database. */ sqlite3_busy_timeout(db, 30000); if (sqlite3_exec(db, CHAR(sql_init), NULL, NULL, NULL) != SQLITE_OK) { log_warn("db: initialization error: %s", sqlite3_errmsg(db)); return -1; } return 0; } int db_project_add(struct project *pj) { assert(pj); sqlite3_stmt *stmt = NULL; int ret = -1; if (sqlite3_prepare(db, CHAR(sql_project_add), -1, &stmt, NULL) != SQLITE_OK) goto sqlite3_err; sqlite3_bind_text(stmt, 1, pj->name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, pj->desc, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, pj->url, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 4, pj->script, -1, SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_DONE) goto sqlite3_err; pj->id = sqlite3_last_insert_rowid(db); ret = 0; sqlite3_err: if (stmt) sqlite3_finalize(stmt); return ret; } ssize_t db_project_list(struct db_ctx *ctx, struct project *projects, size_t projectsz) { assert(projects); sqlite3_stmt *stmt = NULL; struct project *p = projects; ssize_t ret = 0; if (sqlite3_prepare(db, CHAR(sql_project_list), -1, &stmt, NULL) != SQLITE_OK) { log_warn("db: %s", sqlite3_errmsg(db)); return -1; } sqlite3_bind_int(stmt, 1, projectsz); ctx->handle = strlist_new(); for (; sqlite3_step(stmt) == SQLITE_ROW && (size_t)ret < projectsz; ++ret, ++p) convert_project(ctx, p, stmt); if (stmt) sqlite3_finalize(stmt); return ret; } int db_project_find(struct db_ctx *ctx, struct project *project) { assert(ctx); assert(project); sqlite3_stmt *stmt = NULL; int ret = -1; ctx->handle = NULL; if (sqlite3_prepare(db, CHAR(sql_project_find), -1, &stmt, NULL) != SQLITE_OK) goto sqlite3_err; sqlite3_bind_text(stmt, 1, project->name, -1, SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_ROW) goto sqlite3_err; ret = 0; ctx->handle = strlist_new(); convert_project(ctx, project, stmt); sqlite3_err: if (ret < 0) { if (ctx->handle) db_ctx_finish(ctx); log_warn("db: %s", sqlite3_errmsg(db)); } if (stmt) sqlite3_finalize(stmt); return ret; } int db_project_find_id(struct db_ctx *ctx, struct project *project) { assert(ctx); assert(project); sqlite3_stmt *stmt = NULL; int ret = -1; ctx->handle = NULL; if (sqlite3_prepare(db, CHAR(sql_project_find_id), -1, &stmt, NULL) != SQLITE_OK) goto sqlite3_err; sqlite3_bind_int(stmt, 1, project->id); if (sqlite3_step(stmt) != SQLITE_ROW) goto sqlite3_err; ret = 0; ctx->handle = strlist_new(); convert_project(ctx, project, stmt); sqlite3_err: if (ret < 0) { if (ctx->handle) db_ctx_finish(ctx); log_warn("db: %s", sqlite3_errmsg(db)); } if (stmt) sqlite3_finalize(stmt); return ret; } int db_worker_add(struct worker *wk) { assert(wk); sqlite3_stmt *stmt = NULL; int ret = -1; if (sqlite3_prepare(db, CHAR(sql_worker_add), -1, &stmt, NULL) != SQLITE_OK) goto sqlite3_err; sqlite3_bind_text(stmt, 1, wk->name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, wk->desc, -1, SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_DONE) goto sqlite3_err; wk->id = sqlite3_last_insert_rowid(db); ret = 0; sqlite3_err: if (stmt) sqlite3_finalize(stmt); return ret; } ssize_t db_worker_list(struct db_ctx *ctx, struct worker *wk, size_t wksz) { assert(ctx); assert(wk); sqlite3_stmt *stmt = NULL; struct worker *w = wk; ssize_t ret = -1; ctx->handle = NULL; if (sqlite3_prepare(db, CHAR(sql_worker_list), -1, &stmt, NULL) != SQLITE_OK) goto sqlite3_err; sqlite3_bind_int(stmt, 1, wksz); ctx->handle = strlist_new(); for (ret = 0; sqlite3_step(stmt) == SQLITE_ROW && (size_t)ret < wksz; ++ret, ++w) { w->id = sqlite3_column_int(stmt, 0); w->name = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 1))); w->desc = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 2))); } sqlite3_err: if (ret < 0) { if (ctx->handle) db_ctx_finish(ctx); log_warn("db: %s", sqlite3_errmsg(db)); } if (stmt) sqlite3_finalize(stmt); return ret; } int db_worker_find(struct db_ctx *ctx, struct worker *w) { assert(ctx); assert(w); sqlite3_stmt *stmt = NULL; int ret = -1; ctx->handle = NULL; if (sqlite3_prepare(db, CHAR(sql_worker_find), -1, &stmt, NULL) != SQLITE_OK) goto sqlite3_err; sqlite3_bind_text(stmt, 1, w->name, -1, SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_ROW) goto sqlite3_err; ret = 0; ctx->handle = strlist_new(); w->id = sqlite3_column_int(stmt, 0); w->name = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 1))); w->desc = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 2))); sqlite3_err: if (ret < 0) { if (ctx->handle) db_ctx_finish(ctx); log_warn("db: %s", sqlite3_errmsg(db)); } if (stmt) sqlite3_finalize(stmt); return ret; } int db_worker_find_id(struct db_ctx *ctx, struct worker *w) { assert(ctx); assert(w); sqlite3_stmt *stmt = NULL; int ret = -1; ctx->handle = NULL; if (sqlite3_prepare(db, CHAR(sql_worker_find_id), -1, &stmt, NULL) != SQLITE_OK) goto sqlite3_err; sqlite3_bind_int(stmt, 1, w->id); if (sqlite3_step(stmt) != SQLITE_ROW) goto sqlite3_err; ret = 0; ctx->handle = strlist_new(); w->id = sqlite3_column_int(stmt, 0); w->name = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 1))); w->desc = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 2))); sqlite3_err: if (ret < 0) { if (ctx->handle) db_ctx_finish(ctx); log_warn("db: %s", sqlite3_errmsg(db)); } if (stmt) sqlite3_finalize(stmt); return ret; } int db_job_add(struct job *job) { assert(job); job->id = insert(CHAR(sql_job_add), "si", job->tag, job->project_id); return job->id < 0 ? -1 : 0; } ssize_t db_job_todo(struct db_ctx *ctx, struct job *jobs, size_t jobsz, int worker_id) { assert(ctx); assert(jobs); sqlite3_stmt *stmt = NULL; ssize_t ret = 0; if (sqlite3_prepare(db, CHAR(sql_job_todo), -1, &stmt, NULL) != SQLITE_OK) { log_warn("db: %s", sqlite3_errmsg(db)); return -1; } sqlite3_bind_int(stmt, 1, worker_id); sqlite3_bind_int(stmt, 2, jobsz); ctx->handle = strlist_new(); while (sqlite3_step(stmt) == SQLITE_ROW && (size_t)ret++ < jobsz) { jobs->id = sqlite3_column_int(stmt, 0); jobs->tag = strlist_add(ctx->handle, CHAR(sqlite3_column_text(stmt, 1))); jobs++->project_id = sqlite3_column_int(stmt, 2); }; sqlite3_finalize(stmt); return ret; } int db_jobresult_add(struct jobresult *r) { assert(r); r->id = insert(CHAR(sql_jobresult_add), "iiis", r->job_id, r->worker_id, r->exitcode, r->log); return r->id < 0 ? -1 : 0; } void db_finish(void) { if (db) { sqlite3_close(db); db = NULL; } } void db_ctx_finish(struct db_ctx *ctx) { if (ctx->handle) { strlist_free(ctx->handle); ctx->handle = NULL; } }