diff database.c @ 79:52029a52a385

pasterd: revert using ktemplate
author David Demelier <markand@malikania.fr>
date Fri, 17 Mar 2023 07:43:20 +0100
parents 9bfe5ce3cc45
children 94dcca86e5cc
line wrap: on
line diff
--- a/database.c	Thu Mar 16 20:45:59 2023 +0100
+++ b/database.c	Fri Mar 17 07:43:20 2023 +0100
@@ -24,8 +24,8 @@
 #include <sqlite3.h>
 
 #include "database.h"
-#include "json-util.h"
 #include "log.h"
+#include "paste.h"
 #include "util.h"
 
 #include "sql/clear.h"
@@ -35,23 +35,27 @@
 #include "sql/recents.h"
 #include "sql/search.h"
 
-#define ID_MAX (12 + 1)
+#define CHAR(sql) (const char *)(sql)
 
 static sqlite3 *db;
 
-static inline json_t *
-convert(sqlite3_stmt *stmt)
+static char *
+dup(const unsigned char *s)
+{
+	return estrdup(s ? (const char *)(s) : "");
+}
+
+static void
+convert(sqlite3_stmt *stmt, struct paste *paste)
 {
-	return json_pack("{ss ss ss ss ss sI si si}",
-		"id",           sqlite3_column_text(stmt, 0),
-		"title",        sqlite3_column_text(stmt, 1),
-		"author",       sqlite3_column_text(stmt, 2),
-		"language",     sqlite3_column_text(stmt, 3),
-		"code",         sqlite3_column_text(stmt, 4),
-		"timestamp",    (json_int_t)sqlite3_column_int64(stmt, 5),
-		"visible",      sqlite3_column_int(stmt, 6),
-		"duration",     sqlite3_column_int(stmt, 7)
-	);
+	paste->id = dup(sqlite3_column_text(stmt, 0));
+	paste->title = dup(sqlite3_column_text(stmt, 1));
+	paste->author = dup(sqlite3_column_text(stmt, 2));
+	paste->language = dup(sqlite3_column_text(stmt, 3));
+	paste->code = dup(sqlite3_column_text(stmt, 4));
+	paste->timestamp = sqlite3_column_int64(stmt, 5);
+	paste->visible = sqlite3_column_int(stmt, 6);
+	paste->duration = sqlite3_column_int64(stmt, 7);
 }
 
 static int
@@ -62,7 +66,7 @@
 	sqlite3_stmt *stmt = NULL;
 	int ret = 1;
 
-	if (sqlite3_prepare(db, sql_get, -1, &stmt, NULL) == SQLITE_OK) {
+	if (sqlite3_prepare(db, CHAR(sql_get), -1, &stmt, NULL) == SQLITE_OK) {
 		sqlite3_bind_text(stmt, 1, id, -1, NULL);
 		ret = sqlite3_step(stmt) == SQLITE_ROW;
 		sqlite3_finalize(stmt);
@@ -72,19 +76,24 @@
 }
 
 static const char *
-create_id(char *id)
+create_id(void)
 {
 	static const char table[] = "abcdefghijklmnopqrstuvwxyz1234567890";
+	static char id[12];
 
-	for (int i = 0; i < ID_MAX; ++i)
+	for (size_t i = 0; i < sizeof (id); ++i)
 		id[i] = table[rand() % (sizeof (table) - 1)];
 
-	id[ID_MAX - 1] = 0;
+	return id;
 }
 
 static int
-set_id(json_t *paste)
+set_id(struct paste *paste)
 {
+	assert(paste);
+
+	paste->id = NULL;
+
 	/*
 	 * Avoid infinite loop, we only try to create a new id in 30 steps.
 	 *
@@ -92,18 +101,13 @@
 	 * not try to save with that id.
 	 */
 	int tries = 0;
-	char id[ID_MAX];
 
 	do {
-		create_id(id);
-	} while (++tries < 30 && exists(id));
+		free(paste->id);
+		paste->id = estrdup(create_id());
+	} while (++tries < 30 && exists(paste->id));
 
-	if (tries >= 30)
-		return -1;
-
-	json_object_set_new(paste, "id", json_string(id));
-
-	return 0;
+	return tries < 30 ? 0 : -1;
 }
 
 int
@@ -121,7 +125,7 @@
 	/* Wait for 30 seconds to lock the database. */
 	sqlite3_busy_timeout(db, 30000);
 
-	if (sqlite3_exec(db, sql_init, NULL, NULL, NULL) != SQLITE_OK) {
+	if (sqlite3_exec(db, CHAR(sql_init), NULL, NULL, NULL) != SQLITE_OK) {
 		log_warn("database: unable to initialize %s: %s", path, sqlite3_errmsg(db));
 		return -1;
 	}
@@ -129,28 +133,30 @@
 	return 0;
 }
 
-json_t *
-database_recents(size_t limit)
+int
+database_recents(struct paste *pastes, size_t *max)
 {
-	json_t *array = NULL;
+	assert(pastes);
+	assert(max);
+
 	sqlite3_stmt *stmt = NULL;
 	size_t i = 0;
 
+	memset(pastes, 0, *max * sizeof (struct paste));
 	log_debug("database: accessing most recents");
 
-	if (sqlite3_prepare(db, sql_recents, -1, &stmt, NULL) != SQLITE_OK ||
-	    sqlite3_bind_int64(stmt, 1, limit) != SQLITE_OK)
+	if (sqlite3_prepare(db, CHAR(sql_recents), -1, &stmt, NULL) != SQLITE_OK ||
+	    sqlite3_bind_int64(stmt, 1, *max) != SQLITE_OK)
 		goto sqlite_err;
 
-	array = json_array();
-
-	for (; i < limit && sqlite3_step(stmt) == SQLITE_ROW; ++i)
-		json_array_append_new(array, convert(stmt));
+	for (; i < *max && sqlite3_step(stmt) == SQLITE_ROW; ++i)
+		convert(stmt, &pastes[i]);
 
 	log_debug("database: found %zu pastes", i);
 	sqlite3_finalize(stmt);
+	*max = i;
 
-	return array;
+	return 0;
 
 sqlite_err:
 	log_warn("database: error (recents): %s\n", sqlite3_errmsg(db));
@@ -158,26 +164,31 @@
 	if (stmt)
 		sqlite3_finalize(stmt);
 
-	return NULL;
+	*max = 0;
+
+	return -1;
 }
 
-json_t *
-database_get(const char *id)
+int
+database_get(struct paste *paste, const char *id)
 {
+	assert(paste);
 	assert(id);
 
-	json_t *object = NULL;
 	sqlite3_stmt* stmt = NULL;
+	int found = -1;
 
-	log_debug("database: accessing paste with uuid: %s", id);
+	memset(paste, 0, sizeof (struct paste));
+	log_debug("database: accessing paste with id: %s", id);
 
-	if (sqlite3_prepare(db, sql_get, -1, &stmt, NULL) != SQLITE_OK ||
+	if (sqlite3_prepare(db, CHAR(sql_get), -1, &stmt, NULL) != SQLITE_OK ||
 	    sqlite3_bind_text(stmt, 1, id, -1, NULL) != SQLITE_OK)
 		goto sqlite_err;
 
 	switch (sqlite3_step(stmt)) {
 	case SQLITE_ROW:
-		object = convert(stmt);
+		convert(stmt, paste);
+		found = 0;
 		break;
 	case SQLITE_MISUSE:
 	case SQLITE_ERROR:
@@ -188,7 +199,7 @@
 
 	sqlite3_finalize(stmt);
 
-	return object;
+	return found;
 
 sqlite_err:
 	if (stmt)
@@ -196,11 +207,11 @@
 
 	log_warn("database: error (get): %s", sqlite3_errmsg(db));
 
-	return NULL;
+	return -1;
 }
 
 int
-database_insert(json_t *paste)
+database_insert(struct paste *paste)
 {
 	assert(paste);
 
@@ -212,23 +223,21 @@
 		log_warn("database: could not lock database: %s", sqlite3_errmsg(db));
 		return -1;
 	}
-
 	if (set_id(paste) < 0) {
 		log_warn("database: unable to randomize unique identifier");
 		sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL);
 		return -1;
 	}
-
-	if (sqlite3_prepare(db, sql_insert, -1, &stmt, NULL) != SQLITE_OK)
+	if (sqlite3_prepare(db, CHAR(sql_insert), -1, &stmt, NULL) != SQLITE_OK)
 		goto sqlite_err;
 
-	sqlite3_bind_text(stmt, 1, ju_get_string(paste, "id"), -1, SQLITE_STATIC);
-	sqlite3_bind_text(stmt, 2, ju_get_string(paste, "title"), -1, SQLITE_STATIC);
-	sqlite3_bind_text(stmt, 3, ju_get_string(paste, "author"), -1, SQLITE_STATIC);
-	sqlite3_bind_text(stmt, 4, ju_get_string(paste, "language"), -1, SQLITE_STATIC);
-	sqlite3_bind_text(stmt, 5, ju_get_string(paste, "code"), -1, SQLITE_STATIC);
-	sqlite3_bind_int(stmt, 6, ju_get_bool(paste, "visible"));
-	sqlite3_bind_int64(stmt, 7, ju_get_int(paste, "duration"));
+	sqlite3_bind_text(stmt, 1, paste->id, -1, SQLITE_STATIC);
+	sqlite3_bind_text(stmt, 2, paste->title, -1, SQLITE_STATIC);
+	sqlite3_bind_text(stmt, 3, paste->author, -1, SQLITE_STATIC);
+	sqlite3_bind_text(stmt, 4, paste->language, -1, SQLITE_STATIC);
+	sqlite3_bind_text(stmt, 5, paste->code, -1, SQLITE_STATIC);
+	sqlite3_bind_int(stmt, 6, paste->visible);
+	sqlite3_bind_int64(stmt, 7, paste->duration);
 
 	if (sqlite3_step(stmt) != SQLITE_DONE)
 		goto sqlite_err;
@@ -237,10 +246,7 @@
 	sqlite3_finalize(stmt);
 
 	log_info("database: new paste (%s) from %s expires in one %lld seconds",
-	    ju_get_string(paste, "id"),
-	    ju_get_string(paste, "author"),
-	    ju_get_int(paste, "duration")
-	);
+	    paste->id, paste->author, paste->duration);
 
 	return 0;
 
@@ -251,19 +257,22 @@
 	if (stmt)
 		sqlite3_finalize(stmt);
 
-	/* Make sure it is not used anymore. */
-	json_object_del(paste, "id");
+	free(paste->id);
+	paste->id = NULL;
 
-	return 0;
+	return -1;
 }
 
-json_t *
-database_search(size_t limit,
+int
+database_search(struct paste *pastes,
+                size_t *max,
                 const char *title,
                 const char *author,
                 const char *language)
 {
-	json_t *array = NULL;
+	assert(pastes);
+	assert(max);
+
 	sqlite3_stmt *stmt = NULL;
 	size_t i = 0;
 
@@ -272,12 +281,14 @@
 	    author   ? author   : "",
 	    language ? language : "");
 
+	memset(pastes, 0, *max * sizeof (struct paste));
+
 	/* Select everything if not specified. */
 	title    = title    ? title    : "%";
 	author   = author   ? author   : "%";
 	language = language ? language : "%";
 
-	if (sqlite3_prepare(db, sql_search, -1, &stmt, NULL) != SQLITE_OK)
+	if (sqlite3_prepare(db, CHAR(sql_search), -1, &stmt, NULL) != SQLITE_OK)
 		goto sqlite_err;
 	if (sqlite3_bind_text(stmt, 1, title, -1, NULL) != SQLITE_OK)
 		goto sqlite_err;
@@ -285,18 +296,17 @@
 		goto sqlite_err;
 	if (sqlite3_bind_text(stmt, 3, language, -1, NULL) != SQLITE_OK)
 		goto sqlite_err;
-	if (sqlite3_bind_int64(stmt, 4, limit) != SQLITE_OK)
+	if (sqlite3_bind_int64(stmt, 4, *max) != SQLITE_OK)
 		goto sqlite_err;
 
-	array = json_array();
-
-	for (; i < limit && sqlite3_step(stmt) == SQLITE_ROW; ++i)
-		json_array_append_new(array, convert(stmt));
+	for (; i < *max && sqlite3_step(stmt) == SQLITE_ROW; ++i)
+		convert(stmt, &pastes[i]);
 
 	log_debug("database: found %zu pastes", i);
 	sqlite3_finalize(stmt);
+	*max = i;
 
-	return array;
+	return 0;
 
 sqlite_err:
 	log_warn("database: error (search): %s\n", sqlite3_errmsg(db));
@@ -304,7 +314,9 @@
 	if (stmt)
 		sqlite3_finalize(stmt);
 
-	return NULL;
+	*max = 0;
+
+	return -1;
 }
 
 void
@@ -312,7 +324,7 @@
 {
 	log_debug("database: clearing deprecated pastes");
 
-	if (sqlite3_exec(db, sql_clear, NULL, NULL, NULL) != SQLITE_OK)
+	if (sqlite3_exec(db, CHAR(sql_clear), NULL, NULL, NULL) != SQLITE_OK)
 		log_warn("database: error (clear): %s\n", sqlite3_errmsg(db));
 }