Mercurial
diff deita/d_sqlite.c @ 75:ae6a88e6e484
[Deita] Simple DB connection lib.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 31 Dec 2025 11:20:08 -0800 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/deita/d_sqlite.c Wed Dec 31 11:20:08 2025 -0800 @@ -0,0 +1,327 @@ +#include "deita_internal.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +Deita_Connection* deita__sqlite_connection_create(const char *connection_string) +{ + Deita_Connection *p_connection = (Deita_Connection*)malloc(sizeof(Deita_Connection)); + if (!p_connection) + { + fprintf(stderr, "deita__sqlite_connection_create: Failed to allocate connection\n"); + return NULL; + } + + p_connection->database_type = DEITA_DATABASE_TYPE_SQLITE3; + p_connection->native_handle = NULL; + p_connection->is_open = FALSE; + + sqlite3 *p_db = NULL; + int32 result = sqlite3_open(connection_string, &p_db); + + if (result != SQLITE_OK) + { + fprintf(stderr, "deita__sqlite_connection_create: Failed to open database: %s\n", sqlite3_errmsg(p_db)); + sqlite3_close(p_db); + free(p_connection); + return NULL; + } + + p_connection->native_handle = p_db; + p_connection->is_open = TRUE; + + return p_connection; +} + +void deita__sqlite_connection_close(Deita_Connection *p_connection) +{ + if (!p_connection) + return; + + if (p_connection->native_handle) + { + sqlite3 *p_db = (sqlite3*)p_connection->native_handle; + sqlite3_close(p_db); + p_connection->native_handle = NULL; + } + + p_connection->is_open = FALSE; + free(p_connection); +} + +boolean deita__sqlite_connection_is_open(Deita_Connection *p_connection) +{ + if (!p_connection) + return FALSE; + + return p_connection->is_open; +} + +Deita_Result_Set* deita__sqlite_query_execute( + Deita_Connection *p_connection, + const char *query, + Dowa_Arena *p_arena) +{ + if (!p_connection || !p_connection->native_handle || !query) + return NULL; + + sqlite3 *p_db = (sqlite3*)p_connection->native_handle; + sqlite3_stmt *p_stmt = NULL; + + int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL); + if (result != SQLITE_OK) + { + fprintf(stderr, "deita__sqlite_query_execute: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db)); + return NULL; + } + + Deita_Result_Set *p_result_set = (Deita_Result_Set*)Dowa_Arena_Allocate(p_arena, sizeof(Deita_Result_Set)); + if (!p_result_set) + { + fprintf(stderr, "deita__sqlite_query_execute: Failed to allocate result set\n"); + sqlite3_finalize(p_stmt); + return NULL; + } + + p_result_set->database_type = DEITA_DATABASE_TYPE_SQLITE3; + p_result_set->native_result = p_stmt; + p_result_set->column_count = sqlite3_column_count(p_stmt); + p_result_set->has_data = FALSE; + p_result_set->is_done = FALSE; + + return p_result_set; +} + +Deita_Result_Set* deita__sqlite_query_execute_prepared( + Deita_Connection *p_connection, + const char *query, + int32 parameter_count, + const char **parameter_values, + Dowa_Arena *p_arena) +{ + if (!p_connection || !p_connection->native_handle || !query) + return NULL; + + sqlite3 *p_db = (sqlite3*)p_connection->native_handle; + sqlite3_stmt *p_stmt = NULL; + + int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL); + if (result != SQLITE_OK) + { + fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db)); + return NULL; + } + + for (int32 i = 0; i < parameter_count; i++) + { + result = sqlite3_bind_text(p_stmt, i + 1, parameter_values[i], -1, SQLITE_TRANSIENT); + if (result != SQLITE_OK) + { + fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to bind parameter %d: %s\n", i, sqlite3_errmsg(p_db)); + sqlite3_finalize(p_stmt); + return NULL; + } + } + + Deita_Result_Set *p_result_set = (Deita_Result_Set*)Dowa_Arena_Allocate(p_arena, sizeof(Deita_Result_Set)); + if (!p_result_set) + { + fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to allocate result set\n"); + sqlite3_finalize(p_stmt); + return NULL; + } + + p_result_set->database_type = DEITA_DATABASE_TYPE_SQLITE3; + p_result_set->native_result = p_stmt; + p_result_set->column_count = sqlite3_column_count(p_stmt); + p_result_set->has_data = FALSE; + p_result_set->is_done = FALSE; + + return p_result_set; +} + +int32 deita__sqlite_query_execute_update( + Deita_Connection *p_connection, + const char *query) +{ + if (!p_connection || !p_connection->native_handle || !query) + return -1; + + sqlite3 *p_db = (sqlite3*)p_connection->native_handle; + char *error_message = NULL; + + int32 result = sqlite3_exec(p_db, query, NULL, NULL, &error_message); + if (result != SQLITE_OK) + { + fprintf(stderr, "deita__sqlite_query_execute_update: Failed to execute: %s\n", error_message); + sqlite3_free(error_message); + return -1; + } + + return sqlite3_changes(p_db); +} + +int32 deita__sqlite_query_execute_update_prepared( + Deita_Connection *p_connection, + const char *query, + int32 parameter_count, + const char **parameter_values) +{ + if (!p_connection || !p_connection->native_handle || !query) + return -1; + + sqlite3 *p_db = (sqlite3*)p_connection->native_handle; + sqlite3_stmt *p_stmt = NULL; + + int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL); + if (result != SQLITE_OK) + { + fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db)); + return -1; + } + + for (int32 i = 0; i < parameter_count; i++) + { + result = sqlite3_bind_text(p_stmt, i + 1, parameter_values[i], -1, SQLITE_TRANSIENT); + if (result != SQLITE_OK) + { + fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to bind parameter %d: %s\n", i, sqlite3_errmsg(p_db)); + sqlite3_finalize(p_stmt); + return -1; + } + } + + result = sqlite3_step(p_stmt); + if (result != SQLITE_DONE) + { + fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to execute: %s\n", sqlite3_errmsg(p_db)); + sqlite3_finalize(p_stmt); + return -1; + } + + int32 changes = sqlite3_changes(p_db); + sqlite3_finalize(p_stmt); + + return changes; +} + +boolean deita__sqlite_result_set_next(Deita_Result_Set *p_result_set) +{ + if (!p_result_set || !p_result_set->native_result || p_result_set->is_done) + return FALSE; + + sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; + int32 result = sqlite3_step(p_stmt); + + if (result == SQLITE_ROW) + { + p_result_set->has_data = TRUE; + return TRUE; + } + else if (result == SQLITE_DONE) + { + p_result_set->has_data = FALSE; + p_result_set->is_done = TRUE; + return FALSE; + } + else + { + fprintf(stderr, "deita__sqlite_result_set_next: Error stepping through results\n"); + p_result_set->has_data = FALSE; + p_result_set->is_done = TRUE; + return FALSE; + } +} + +int32 deita__sqlite_result_set_get_column_count(Deita_Result_Set *p_result_set) +{ + if (!p_result_set) + return 0; + + return p_result_set->column_count; +} + +const char* deita__sqlite_result_set_get_column_name( + Deita_Result_Set *p_result_set, + int32 column_index) +{ + if (!p_result_set || !p_result_set->native_result) + return NULL; + + sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; + return sqlite3_column_name(p_stmt, column_index); +} + +Deita_Column_Type deita__sqlite_result_set_get_column_type( + Deita_Result_Set *p_result_set, + int32 column_index) +{ + if (!p_result_set || !p_result_set->native_result) + return DEITA_COLUMN_TYPE_NULL; + + sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; + int32 sqlite_type = sqlite3_column_type(p_stmt, column_index); + + switch (sqlite_type) + { + case SQLITE_INTEGER: + return DEITA_COLUMN_TYPE_INTEGER; + case SQLITE_FLOAT: + return DEITA_COLUMN_TYPE_REAL; + case SQLITE_TEXT: + return DEITA_COLUMN_TYPE_TEXT; + case SQLITE_BLOB: + return DEITA_COLUMN_TYPE_BLOB; + case SQLITE_NULL: + default: + return DEITA_COLUMN_TYPE_NULL; + } +} + +const char* deita__sqlite_result_set_get_text( + Deita_Result_Set *p_result_set, + int32 column_index) +{ + if (!p_result_set || !p_result_set->native_result) + return NULL; + + sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; + const unsigned char *text = sqlite3_column_text(p_stmt, column_index); + + return (const char*)text; +} + +int64 deita__sqlite_result_set_get_integer( + Deita_Result_Set *p_result_set, + int32 column_index) +{ + if (!p_result_set || !p_result_set->native_result) + return 0; + + sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; + return sqlite3_column_int64(p_stmt, column_index); +} + +double deita__sqlite_result_set_get_real( + Deita_Result_Set *p_result_set, + int32 column_index) +{ + if (!p_result_set || !p_result_set->native_result) + return 0.0; + + sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; + return sqlite3_column_double(p_stmt, column_index); +} + +void deita__sqlite_result_set_free(Deita_Result_Set *p_result_set) +{ + if (!p_result_set) + return; + + if (p_result_set->native_result) + { + sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; + sqlite3_finalize(p_stmt); + p_result_set->native_result = NULL; + } +}