#include #include #include #include #include #include sqlite3 *global_database; static database_transaction_lock *transaction_lock; void database_init() { int rc = sqlite3_open(global_config.database, &global_database); if(rc) { LOGGER_CRIT("can't open database: %s\n", sqlite3_errmsg(global_database)); exit(1); } database_migrate(); sqlite3_exec(global_database, "PRAGMA foreign_keys = ON", 0, 0, 0); transaction_lock = NULL; } void database_free() { sqlite3_close(global_database); } static void database_migrate_step_simple(int level, const char* sql_migration) { LOGGER_INFO("migrating LEVEL %d\n", level); char* err_msg; sqlite3_exec(global_database, "BEGIN TRANSACTION;", NULL, NULL, NULL); int rc = sqlite3_exec(global_database, sql_migration, NULL, NULL, &err_msg); if(rc) { LOGGER_CRIT("couldn't migrate LEVEL %d (%s)\n", level, err_msg); sqlite3_exec(global_database, "ROLLBACK TRANSACTION;", NULL, NULL, NULL); exit(1); } LOGGER_DEBUG("storing new user_version %d\n", level + 1); char pragma_query[32]; sprintf(pragma_query, "PRAGMA user_version=%d;", level + 1); sqlite3_exec(global_database, pragma_query, 0, 0, 0); sqlite3_exec(global_database, "COMMIT TRANSACTION;", NULL, NULL, NULL); } void database_migrate() { uint16_t version_num = 0; int s; sqlite3_stmt *stmt; sqlite3_prepare_v2(global_database, "PRAGMA user_version;", -1, &stmt, NULL); s = sqlite3_step(stmt); if (s == SQLITE_ROW) { version_num = sqlite3_column_int(stmt, 0); } else { version_num = 0; } sqlite3_finalize(stmt); switch(version_num) { case 0: database_migrate_step_simple(0, (const char*)sql_migration_0_sql); __attribute__ ((fallthrough)); case 1: database_migrate_step_simple(1, (const char*)sql_migration_1_sql); __attribute__ ((fallthrough)); default: break; } return; } void database_transaction_begin(database_transaction_lock *lock) { if(transaction_lock == NULL) { LOGGER_DEBUG("beginning transaction\n"); sqlite3_exec(global_database, "BEGIN TRANSACTION;", NULL, NULL, NULL); transaction_lock = lock; } } void database_transaction_commit(database_transaction_lock *lock) { if(transaction_lock == lock) { LOGGER_DEBUG("commiting transaction\n"); sqlite3_exec(global_database, "COMMIT TRANSACTION;", NULL, NULL, NULL); transaction_lock = NULL; } } void database_transaction_rollback(database_transaction_lock *lock) { if(transaction_lock == lock) { LOGGER_DEBUG("rolling back transaction\n"); sqlite3_exec(global_database, "ROLLBACK TRANSACTION;", NULL, NULL, NULL); transaction_lock = NULL; } } int database_helper_get_id(sqlite3_stmt *stmt) { int result = 0; for(;;) { int s; s = sqlite3_step(stmt); if (s == SQLITE_ROW) { result = sqlite3_column_int(stmt, 0); } else { if (s == SQLITE_DONE) { break; } else { LOGGER_ERR("error selecting id from database: %s\n", sqlite3_errstr(s)); sqlite3_finalize(stmt); return 0; } } } sqlite3_finalize(stmt); return result; } int* database_helper_get_ids(sqlite3_stmt *stmt) { int *result = malloc(sizeof(int)); int new_id; int row = 0; for(;;) { int s; s = sqlite3_step(stmt); if (s == SQLITE_ROW) { new_id = sqlite3_column_int(stmt, 0); if(new_id != 0) // found row for other target (relay <> schedule) { row++; result = (int*)realloc(result, sizeof(int) * (row + 1)); result[row - 1] = new_id; } } else { if (s == SQLITE_DONE) { break; } else { LOGGER_ERR("error selecting ids from database: %s\n", sqlite3_errstr(s)); sqlite3_finalize(stmt); return NULL; } } } sqlite3_finalize(stmt); result[row] = 0; return result; } char* database_helper_get_string(sqlite3_stmt *stmt) { char *result = NULL; for(;;) { int s; s = sqlite3_step(stmt); if (s == SQLITE_ROW) { const char *found_string = (const char *)sqlite3_column_text(stmt, 0); result = (char*)malloc(sizeof(char) * (strlen(found_string) + 1)); strcpy(result, found_string); } else { if (s == SQLITE_DONE) { break; } else { LOGGER_ERR("error selecting string from database: %s\n", sqlite3_errstr(s)); sqlite3_finalize(stmt); return NULL; } } } sqlite3_finalize(stmt); return result; } char** database_helper_get_strings(sqlite3_stmt *stmt) { char **result = malloc(sizeof(char*)); int row = 0; for(;;) { int s; s = sqlite3_step(stmt); if (s == SQLITE_ROW) { const char *new_string = (const char *)sqlite3_column_text(stmt, 0); int new_string_len = strlen(new_string); row++; result = (char**)realloc(result, sizeof(char*) * (row + 1)); result[row - 1] = malloc(sizeof(char) * (new_string_len + 1)); strcpy(result[row - 1], new_string); } else { if(s == SQLITE_DONE) { break; } else { LOGGER_ERR("error selecting strings from database: %s\n", sqlite3_errstr(s)); break; } } } sqlite3_finalize(stmt); result[row] = NULL; return result; }