diff 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 diff
--- a/db.c	Thu Jun 10 10:39:21 2021 +0200
+++ b/db.c	Mon Jun 14 22:08:24 2021 +0200
@@ -1,3 +1,4 @@
+#include <sys/queue.h>
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
@@ -5,34 +6,117 @@
 #include <sqlite3.h>
 
 #include "db.h"
-#include "job.h"
 #include "log.h"
-#include "project.h"
-#include "worker.h"
+#include "types.h"
+#include "util.h"
 
 #include "sql/init.h"
-#include "sql/job-queue.h"
-#include "sql/job-result-todo.h"
-#include "sql/job-save.h"
-#include "sql/project-insert.h"
-#include "sql/project-get.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/worker-get.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-insert.h"
+#include "sql/worker-find-id.h"
+#include "sql/worker-list.h"
 
 #define CHAR(v) (const char *)(v)
 
 static sqlite3 *db;
 
-static inline void
-convert_project(struct project *project, sqlite3_stmt *stmt)
+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)
 {
-	project->id = sqlite3_column_int64(stmt, 0);
-	strlcpy(project->name, CHAR(sqlite3_column_text(stmt, 1)), sizeof (project->name));
-	strlcpy(project->desc, CHAR(sqlite3_column_text(stmt, 2)), sizeof (project->desc));
-	strlcpy(project->url, CHAR(sqlite3_column_text(stmt, 3)), sizeof (project->url));
-	strlcpy(project->script, CHAR(sqlite3_column_text(stmt, 4)), sizeof (project->script));
+	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
@@ -64,7 +148,7 @@
 	sqlite3_stmt *stmt = NULL;
 	int ret = -1;
 
-	if (sqlite3_prepare(db, CHAR(sql_project_insert), -1, &stmt, NULL) != SQLITE_OK)
+	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);
@@ -86,7 +170,7 @@
 }
 
 ssize_t
-db_project_get(struct project *projects, size_t projectsz)
+db_project_list(struct db_ctx *ctx, struct project *projects, size_t projectsz)
 {
 	assert(projects);
 
@@ -94,15 +178,16 @@
 	struct project *p = projects;
 	ssize_t ret = 0;
 
-	if (sqlite3_prepare(db, CHAR(sql_project_get), -1, &stmt, NULL) != SQLITE_OK) {
+	if (sqlite3_prepare(db, CHAR(sql_project_list), -1, &stmt, NULL) != SQLITE_OK) {
 		log_warn("db: %s", sqlite3_errmsg(db));
 		return -1;
 	}
 
-	sqlite3_bind_int64(stmt, 1, projectsz);
+	sqlite3_bind_int(stmt, 1, projectsz);
+	ctx->handle = strlist_new();
 
 	for (; sqlite3_step(stmt) == SQLITE_ROW && (size_t)ret < projectsz; ++ret, ++p)
-		convert_project(p, stmt);
+		convert_project(ctx, p, stmt);
 
 	if (stmt)
 		sqlite3_finalize(stmt);
@@ -111,13 +196,16 @@
 }
 
 int
-db_project_find(struct project *project)
+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;
 
@@ -127,11 +215,52 @@
 		goto sqlite3_err;
 
 	ret = 0;
-	convert_project(project, stmt);
+	ctx->handle = strlist_new();
+	convert_project(ctx, project, stmt);
 
 sqlite3_err:
-	if (ret < 0)
+	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);
 
@@ -146,7 +275,7 @@
 	sqlite3_stmt *stmt = NULL;
 	int ret = -1;
 
-	if (sqlite3_prepare(db, CHAR(sql_worker_insert), -1, &stmt, NULL) != SQLITE_OK)
+	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);
@@ -166,28 +295,36 @@
 }
 
 ssize_t
-db_worker_get(struct worker *wk, size_t wksz)
+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;
 
-	if (sqlite3_prepare(db, CHAR(sql_worker_get), -1, &stmt, NULL) != SQLITE_OK)
+	ctx->handle = NULL;
+
+	if (sqlite3_prepare(db, CHAR(sql_worker_list), -1, &stmt, NULL) != SQLITE_OK)
 		goto sqlite3_err;
 
-	sqlite3_bind_int64(stmt, 1, wksz);
+	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_int64(stmt, 0);
-		strlcpy(w->name, CHAR(sqlite3_column_text(stmt, 1)), sizeof (w->name));
-		strlcpy(w->desc, CHAR(sqlite3_column_text(stmt, 2)), sizeof (w->desc));
+		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 (ret < 0) {
+		if (ctx->handle)
+			db_ctx_finish(ctx);
+
 		log_warn("db: %s", sqlite3_errmsg(db));
+	}
 	if (stmt)
 		sqlite3_finalize(stmt);
 
@@ -195,13 +332,16 @@
 }
 
 int
-db_worker_find(struct worker *w)
+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;
 
@@ -211,13 +351,18 @@
 		goto sqlite3_err;
 
 	ret = 0;
-	w->id = sqlite3_column_int64(stmt, 0);
-	strlcpy(w->name, CHAR(sqlite3_column_text(stmt, 1)), sizeof (w->name));
-	strlcpy(w->desc, CHAR(sqlite3_column_text(stmt, 2)), sizeof (w->desc));
+	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 (ret < 0) {
+		if (ctx->handle)
+			db_ctx_finish(ctx);
+
 		log_warn("db: %s", sqlite3_errmsg(db));
+	}
 	if (stmt)
 		sqlite3_finalize(stmt);
 
@@ -225,61 +370,37 @@
 }
 
 int
-db_job_queue(struct job *job)
+db_worker_find_id(struct db_ctx *ctx, struct worker *w)
 {
-	assert(job);
+	assert(ctx);
+	assert(w);
 
 	sqlite3_stmt *stmt = NULL;
 	int ret = -1;
 
-	if (sqlite3_prepare(db, CHAR(sql_job_queue), -1, &stmt, NULL) != SQLITE_OK)
+	ctx->handle = NULL;
+
+	if (sqlite3_prepare(db, CHAR(sql_worker_find_id), -1, &stmt, NULL) != SQLITE_OK)
 		goto sqlite3_err;
 
-	sqlite3_bind_text(stmt, 1, job->tag, -1, SQLITE_STATIC);
-	sqlite3_bind_int64(stmt, 2, job->project.id);
+	sqlite3_bind_int(stmt, 1, w->id);
 
-	if (sqlite3_step(stmt) != SQLITE_DONE)
+	if (sqlite3_step(stmt) != SQLITE_ROW)
 		goto sqlite3_err;
 
-	job->id = sqlite3_last_insert_rowid(db);
 	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)
-		log_warn("db: %s", sqlite3_errmsg(db));
-	if (stmt)
-		sqlite3_finalize(stmt);
-
-	return ret;
-}
+	if (ret < 0) {
+		if (ctx->handle)
+			db_ctx_finish(ctx);
 
-ssize_t
-db_job_result_todo(struct job_result *re, size_t resz, int64_t worker_id)
-{
-	assert(re);
-
-	sqlite3_stmt *stmt = NULL;
-	ssize_t ret = 0;
-
-	if (sqlite3_prepare(db, CHAR(sql_job_result_todo), -1, &stmt, NULL) != SQLITE_OK) {
 		log_warn("db: %s", sqlite3_errmsg(db));
-		return -1;
 	}
-
-	sqlite3_bind_int64(stmt, 1, worker_id);
-	sqlite3_bind_int64(stmt, 2, resz);
-
-	while (sqlite3_step(stmt) == SQLITE_ROW && (size_t)ret++ < resz) {
-		memset(re, 0, sizeof (*re));
-		re->job.id = sqlite3_column_int64(stmt, 0);
-		strlcpy(re->job.tag, CHAR(sqlite3_column_text(stmt, 1)),
-		    sizeof (re->job.tag));
-		strlcpy(re->job.project.name, CHAR(sqlite3_column_text(stmt, 2)),
-		    sizeof (re->job.project.name));
-
-		++re;
-	};
-
 	if (stmt)
 		sqlite3_finalize(stmt);
 
@@ -287,35 +408,53 @@
 }
 
 int
-db_job_save(struct job_result *r)
+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);
 
-	sqlite3_stmt *stmt = NULL;
-	int ret = -1;
-
-	if (sqlite3_prepare(db, CHAR(sql_job_save), -1, &stmt, NULL) != SQLITE_OK)
-		goto sqlite3_err;
-
-	sqlite3_bind_int64(stmt, 1, r->job.id);
-	sqlite3_bind_int64(stmt, 2, r->worker.id);
-	sqlite3_bind_int(stmt, 3, r->status);
-	sqlite3_bind_int(stmt, 4, r->retcode);
-	sqlite3_bind_text(stmt, 5, r->console, -1, SQLITE_STATIC);
+	r->id = insert(CHAR(sql_jobresult_add), "iiis", r->job_id,
+	    r->worker_id, r->exitcode, r->log);
 
-	if (sqlite3_step(stmt) != SQLITE_DONE)
-		goto sqlite3_err;
-
-	ret = 0;
-	r->id = sqlite3_last_insert_rowid(db);
-
-sqlite3_err:
-	if (ret < 0)
-		log_warn("db: %s", sqlite3_errmsg(db));
-	if (stmt)
-		sqlite3_finalize(stmt);
-
-	return ret;
+	return r->id < 0 ? -1 : 0;
 }
 
 void
@@ -326,3 +465,12 @@
 		db = NULL;
 	}
 }
+
+void
+db_ctx_finish(struct db_ctx *ctx)
+{
+	if (ctx->handle) {
+		strlist_free(ctx->handle);
+		ctx->handle = NULL;
+	}
+}