aboutsummaryrefslogtreecommitdiff
path: root/core/sql.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/sql.c')
-rw-r--r--core/sql.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/core/sql.c b/core/sql.c
new file mode 100644
index 0000000..760adc4
--- /dev/null
+++ b/core/sql.c
@@ -0,0 +1,73 @@
+#define DATA_PUSH_BUSY_TIMEOUT 600000
+
+sqlite3 *g_sim_db;
+
+void sql_exec(void (*callback)(sqlite3_stmt *sql_stmt, void *data), void *data, const char *sql_format, ...) {
+ assert(sql_format);
+
+ va_list args;
+ va_start(args, sql_format);
+ int sql_len = vsnprintf(NULL, 0, sql_format, args) + 1;
+ char *sql_str = malloc(sql_len);
+ assert(sql_str);
+ va_end(args);
+
+ va_start(args, sql_format);
+ vsprintf(sql_str, sql_format, args);
+ va_end(args);
+
+ int sql_res;
+ sqlite3_stmt *sql_stmt;
+
+ sql_res = sqlite3_prepare_v2(g_sim_db, sql_str, -1, &sql_stmt, NULL);
+ assert(sql_res == SQLITE_OK);
+ free(sql_str);
+
+ while (true) {
+ sql_res = sqlite3_step(sql_stmt);
+
+ if (sql_res == SQLITE_ROW) {
+ if (callback) {
+ callback(sql_stmt, data);
+ }
+
+ continue;
+ }
+
+ if (sql_res == SQLITE_DONE) {
+ break;
+ }
+
+ log_warn("SQLite database returned error %d with message:", sql_res);
+ log_warn(sqlite3_errmsg(g_sim_db));
+
+ // Only handle SQLITE_BUSY error, in which case we retry the query.
+ // Setting 'journal_mode=wal;' should help prevent busy database errors.
+ if (sql_res == SQLITE_BUSY) {
+ log_info("Will retry query...");
+ continue;
+ }
+
+ assert(false);
+ }
+
+ sqlite3_finalize(sql_stmt);
+}
+
+void sql_open(void) {
+ sqlite3_open(DATA_PUSH_PATH, &g_sim_db);
+ assert(g_sim_db);
+
+ // Install busy handler to retry transactions if DB is locked
+ sqlite3_busy_timeout(g_sim_db, DATA_PUSH_BUSY_TIMEOUT);
+
+ // Enable Write-Ahead Logging (WAL)
+ // This seems to help prevent DB locks when displaying live data.
+ // See: https://sqlite.org/wal.html
+ sql_exec(NULL, NULL, "pragma journal_mode=wal;");
+}
+
+void sql_close(void) {
+ assert(g_sim_db);
+ sqlite3_close(g_sim_db);
+}