summary refs log tree commit diff
path: root/database.h
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-12-24 00:58:26 -0500
committerJune McEnroe <june@causal.agency>2019-12-24 00:58:26 -0500
commit2d7108f29b9f7d80709dfbe0c2e2434b07c5a45c (patch)
tree4e00cf884cd6b0291694f830140d79b240d19c28 /database.h
parentActually only use a transaction for handlers that need it (diff)
downloadlitterbox-2d7108f29b9f7d80709dfbe0c2e2434b07c5a45c.tar.gz
litterbox-2d7108f29b9f7d80709dfbe0c2e2434b07c5a45c.zip
It's The Big Refactor
Diffstat (limited to 'database.h')
-rw-r--r--database.h106
1 files changed, 59 insertions, 47 deletions
diff --git a/database.h b/database.h
index 1d5ef1c..8d8c985 100644
--- a/database.h
+++ b/database.h
@@ -45,13 +45,14 @@ enum Type {
 };
 
 static bool verbose;
+static sqlite3 *db;
 
-static inline void dbExec(sqlite3 *db, const char *sql) {
+static inline void dbExec(const char *sql) {
 	int error = sqlite3_exec(db, sql, NULL, NULL, NULL);
 	if (error) errx(EX_SOFTWARE, "%s: %s", sqlite3_errmsg(db), sql);
 }
 
-static inline sqlite3 *dbOpen(char *path, int flags) {
+static inline void dbOpen(char *path, int flags) {
 	char *base = strrchr(path, '/');
 	if (flags & SQLITE_OPEN_CREATE && base) {
 		*base = '\0';
@@ -60,22 +61,24 @@ static inline sqlite3 *dbOpen(char *path, int flags) {
 		*base = '/';
 	}
 
-	sqlite3 *db;
 	int error = sqlite3_open_v2(path, &db, flags, NULL);
 	if (error == SQLITE_CANTOPEN) {
 		sqlite3_close(db);
-		return NULL;
+		db = NULL;
+		return;
 	}
 	if (error) errx(EX_NOINPUT, "%s: %s", path, sqlite3_errmsg(db));
 
 	sqlite3_busy_timeout(db, 1000);
-	dbExec(db, SQL(PRAGMA foreign_keys = true;));
-
-	return db;
+	dbExec(SQL(PRAGMA foreign_keys = true;));
 }
 
-static inline sqlite3 *dbFind(char *path, int flags) {
-	if (path) return dbOpen(path, flags);
+static inline void dbFind(char *path, int flags) {
+	if (path) {
+		dbOpen(path, flags);
+		if (db) return;
+		errx(EX_NOINPUT, "%s: database not found", path);
+	}
 
 	const char *home = getenv("HOME");
 	const char *dataHome = getenv("XDG_DATA_HOME");
@@ -88,55 +91,71 @@ static inline sqlite3 *dbFind(char *path, int flags) {
 		if (!home) errx(EX_CONFIG, "HOME unset");
 		snprintf(buf, sizeof(buf), "%s/.local/share/" DATABASE_PATH, home);
 	}
-	sqlite3 *db = dbOpen(buf, flags);
-	if (db) return db;
+	dbOpen(buf, flags);
+	if (db) return;
 
 	if (!dataDirs) dataDirs = "/usr/local/share:/usr/share";
 	while (*dataDirs) {
 		size_t len = strcspn(dataDirs, ":");
 		snprintf(buf, sizeof(buf), "%.*s/" DATABASE_PATH, (int)len, dataDirs);
-		db = dbOpen(buf, flags);
-		if (db) return db;
+		dbOpen(buf, flags);
+		if (db) return;
 		dataDirs += len;
 		if (*dataDirs) dataDirs++;
 	}
-	return NULL;
+	errx(EX_NOINPUT, "database not found");
 }
 
-static inline sqlite3_stmt *
-dbPrepare(sqlite3 *db, bool persistent, const char *sql) {
+static struct Persist {
 	sqlite3_stmt *stmt;
+	struct Persist *prev;
+} *persistHead;
+
+static inline void dbPersist(sqlite3_stmt **stmt, const char *sql) {
+	if (*stmt) return;
+
 	int error = sqlite3_prepare_v3(
-		db, sql, -1, (persistent ? SQLITE_PREPARE_PERSISTENT : 0), &stmt, NULL
+		db, sql, -1, SQLITE_PREPARE_PERSISTENT, stmt, NULL
 	);
 	if (error) errx(EX_SOFTWARE, "%s: %s", sqlite3_errmsg(db), sql);
+
+	struct Persist *persist = malloc(sizeof(*persist));
+	persist->stmt = *stmt;
+	persist->prev = persistHead;
+	persistHead = persist;
+}
+
+static inline void dbClose(void) {
+	for (struct Persist *persist = persistHead; persist;) {
+		sqlite3_finalize(persist->stmt);
+		struct Persist *prev = persist->prev;
+		free(persist);
+		persist = prev;
+	}
+	sqlite3_close(db);
+}
+
+static inline sqlite3_stmt *dbPrepare(const char *sql) {
+	sqlite3_stmt *stmt;
+	int error = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+	if (error) err(EX_SOFTWARE, "%s: %s", sqlite3_errmsg(db), sql);
 	return stmt;
 }
 
 static inline int dbParam(sqlite3_stmt *stmt, const char *param) {
 	int index = sqlite3_bind_parameter_index(stmt, param);
 	if (index) return index;
-	errx(
-		EX_SOFTWARE, "no such parameter %s: %s",
-		param, sqlite3_sql(stmt)
-	);
+	errx(EX_SOFTWARE, "no such parameter %s: %s", param, sqlite3_sql(stmt));
 }
 
 static inline void dbBindNull(sqlite3_stmt *stmt, const char *param) {
 	if (!sqlite3_bind_null(stmt, dbParam(stmt, param))) return;
-	errx(
-		EX_SOFTWARE, "sqlite3_bind_null: %s",
-		sqlite3_errmsg(sqlite3_db_handle(stmt))
-	);
+	errx(EX_SOFTWARE, "sqlite3_bind_null: %s", sqlite3_errmsg(db));
 }
 
-static inline void
-dbBindInt(sqlite3_stmt *stmt, const char *param, int value) {
+static inline void dbBindInt(sqlite3_stmt *stmt, const char *param, int value) {
 	if (!sqlite3_bind_int(stmt, dbParam(stmt, param), value)) return;
-	errx(
-		EX_SOFTWARE, "sqlite3_bind_int: %s",
-		sqlite3_errmsg(sqlite3_db_handle(stmt))
-	);
+	errx(EX_SOFTWARE, "sqlite3_bind_int: %s", sqlite3_errmsg(db));
 }
 
 static inline void dbBindText5(
@@ -146,11 +165,7 @@ static inline void dbBindText5(
 	int error = sqlite3_bind_text(
 		stmt, dbParam(stmt, param), text, len, (copy ? SQLITE_TRANSIENT : NULL)
 	);
-	if (!error) return;
-	errx(
-		EX_SOFTWARE, "sqlite3_bind_text: %s",
-		sqlite3_errmsg(sqlite3_db_handle(stmt))
-	);
+	if (error) err(EX_SOFTWARE, "sqlite3_bind_text: %s", sqlite3_errmsg(db));
 }
 
 static inline void
@@ -171,10 +186,7 @@ dbBindTextCopy(sqlite3_stmt *stmt, const char *param, const char *text) {
 static inline int dbStep(sqlite3_stmt *stmt) {
 	int error = sqlite3_step(stmt);
 	if (error == SQLITE_ROW || error == SQLITE_DONE) return error;
-	errx(
-		EX_SOFTWARE, "%s: %s",
-		sqlite3_errmsg(sqlite3_db_handle(stmt)), sqlite3_expanded_sql(stmt)
-	);
+	errx(EX_SOFTWARE, "%s: %s", sqlite3_errmsg(db), sqlite3_expanded_sql(stmt));
 }
 
 static inline void dbRun(sqlite3_stmt *stmt) {
@@ -187,8 +199,8 @@ static inline void dbRun(sqlite3_stmt *stmt) {
 	sqlite3_reset(stmt);
 }
 
-static inline int dbVersion(sqlite3 *db) {
-	sqlite3_stmt *stmt = dbPrepare(db, false, SQL(PRAGMA user_version;));
+static inline int dbVersion(void) {
+	sqlite3_stmt *stmt = dbPrepare(SQL(PRAGMA user_version;));
 	dbStep(stmt);
 	int version = sqlite3_column_int(stmt, 0);
 	sqlite3_finalize(stmt);
@@ -258,16 +270,16 @@ static const char *InitSQL = SQL(
 	COMMIT TRANSACTION;
 );
 
-static inline void dbInit(sqlite3 *db) {
-	dbExec(db, InitSQL);
+static inline void dbInit(void) {
+	dbExec(InitSQL);
 }
 
 static const char *MigrationSQL[] = {
 	NULL,
 };
 
-static inline void dbMigrate(sqlite3 *db) {
-	for (int version = dbVersion(db); version < DatabaseVersion; ++version) {
-		dbExec(db, MigrationSQL[version]);
+static inline void dbMigrate(void) {
+	for (int version = dbVersion(); version < DatabaseVersion; ++version) {
+		dbExec(MigrationSQL[version]);
 	}
 }