view db.c @ 1:5afdb14df924

sci: add support for storing results
author David Demelier <markand@malikania.fr>
date Tue, 08 Jun 2021 08:40:01 +0200
parents f1de39079243
children 5fa3d2f479b2
line wrap: on
line source

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <sqlite3.h>

#include "db.h"
#include "job.h"
#include "log.h"
#include "project.h"
#include "worker.h"

#include "sql/init.h"
#include "sql/job-queue.h"
#include "sql/job-queue-list.h"
#include "sql/job-save.h"
#include "sql/project-insert.h"
#include "sql/project-get.h"
#include "sql/project-find.h"
#include "sql/worker-get.h"
#include "sql/worker-find.h"
#include "sql/worker-insert.h"

#define CHAR(v) (const char *)(v)

static sqlite3 *db;

static inline void
convert_project(struct project *project, sqlite3_stmt *stmt)
{
	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));
}

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_insert), -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_get(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_get), -1, &stmt, NULL) != SQLITE_OK) {
		log_warn("db: %s", sqlite3_errmsg(db));
		return -1;
	}

	sqlite3_bind_int64(stmt, 1, projectsz);

	for (; sqlite3_step(stmt) == SQLITE_ROW && (size_t)ret < projectsz; ++ret, ++p)
		convert_project(p, stmt);

	if (stmt)
		sqlite3_finalize(stmt);

	return ret;
}

int
db_project_find(struct project *project)
{
	assert(project);

	sqlite3_stmt *stmt = NULL;
	int ret = -1;

	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;
	convert_project(project, stmt);

sqlite3_err:
	if (ret < 0)
		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_insert), -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_get(struct worker *wk, size_t wksz)
{
	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)
		goto sqlite3_err;

	sqlite3_bind_int64(stmt, 1, wksz);

	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));
	}

sqlite3_err:
	if (ret < 0)
		log_warn("db: %s", sqlite3_errmsg(db));
	if (stmt)
		sqlite3_finalize(stmt);

	return ret;
}

int
db_worker_find(struct worker *w, const char *name)
{
	assert(w);
	assert(name);

	sqlite3_stmt *stmt = NULL;
	int ret = -1;

	if (sqlite3_prepare(db, CHAR(sql_worker_find), -1, &stmt, NULL) != SQLITE_OK)
		goto sqlite3_err;

	sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC);

	if (sqlite3_step(stmt) != SQLITE_ROW)
		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));

sqlite3_err:
	if (ret < 0)
		log_warn("db: %s", sqlite3_errmsg(db));
	if (stmt)
		sqlite3_finalize(stmt);

	return ret;
}

int
db_job_queue(struct job *job)
{
	assert(job);

	sqlite3_stmt *stmt = NULL;
	int ret = -1;

	if (sqlite3_prepare(db, CHAR(sql_job_queue), -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);

	if (sqlite3_step(stmt) != SQLITE_DONE)
		goto sqlite3_err;

	job->id = sqlite3_last_insert_rowid(db);
	ret = 0;

sqlite3_err:
	if (ret < 0)
		log_warn("db: %s", sqlite3_errmsg(db));
	if (stmt)
		sqlite3_finalize(stmt);

	return ret;
}

ssize_t
db_job_result_todo(struct job_result *re, size_t resz, int64_t project_id)
{
	assert(re);

	sqlite3_stmt *stmt = NULL;
	ssize_t ret = 0;

	if (sqlite3_prepare(db, CHAR(sql_job_queue_list), -1, &stmt, NULL) != SQLITE_OK) {
		log_warn("db: %s", sqlite3_errmsg(db));
		return -1;
	}

	sqlite3_bind_int64(stmt, 1, project_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));

		re->worker.id = sqlite3_column_int64(stmt, 2);
		strlcpy(re->worker.name, CHAR(sqlite3_column_text(stmt, 3)), sizeof (re->worker.name));
		strlcpy(re->worker.desc, CHAR(sqlite3_column_text(stmt, 4)), sizeof (re->worker.desc));

		re->job.project.id = sqlite3_column_int64(stmt, 5);
		strlcpy(re->job.project.name, CHAR(sqlite3_column_text(stmt, 6)), sizeof (re->job.project.name));
		strlcpy(re->job.project.desc, CHAR(sqlite3_column_text(stmt, 7)), sizeof (re->job.project.desc));
		strlcpy(re->job.project.url, CHAR(sqlite3_column_text(stmt, 8)), sizeof (re->job.project.url));
		strlcpy(re->job.project.script, CHAR(sqlite3_column_text(stmt, 9)), sizeof (re->job.project.script));

		++re;
	};

	if (stmt)
		sqlite3_finalize(stmt);

	return ret;
}

int
db_job_save(struct job_result *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);

	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;
}

void
db_finish(void)
{
	if (db) {
		sqlite3_close(db);
		db = NULL;
	}
}