Mercurial
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 74:4b96794c8d59 | 75:ae6a88e6e484 |
|---|---|
| 1 #include "deita_internal.h" | |
| 2 #include <stdio.h> | |
| 3 #include <stdlib.h> | |
| 4 #include <string.h> | |
| 5 | |
| 6 Deita_Connection* deita__sqlite_connection_create(const char *connection_string) | |
| 7 { | |
| 8 Deita_Connection *p_connection = (Deita_Connection*)malloc(sizeof(Deita_Connection)); | |
| 9 if (!p_connection) | |
| 10 { | |
| 11 fprintf(stderr, "deita__sqlite_connection_create: Failed to allocate connection\n"); | |
| 12 return NULL; | |
| 13 } | |
| 14 | |
| 15 p_connection->database_type = DEITA_DATABASE_TYPE_SQLITE3; | |
| 16 p_connection->native_handle = NULL; | |
| 17 p_connection->is_open = FALSE; | |
| 18 | |
| 19 sqlite3 *p_db = NULL; | |
| 20 int32 result = sqlite3_open(connection_string, &p_db); | |
| 21 | |
| 22 if (result != SQLITE_OK) | |
| 23 { | |
| 24 fprintf(stderr, "deita__sqlite_connection_create: Failed to open database: %s\n", sqlite3_errmsg(p_db)); | |
| 25 sqlite3_close(p_db); | |
| 26 free(p_connection); | |
| 27 return NULL; | |
| 28 } | |
| 29 | |
| 30 p_connection->native_handle = p_db; | |
| 31 p_connection->is_open = TRUE; | |
| 32 | |
| 33 return p_connection; | |
| 34 } | |
| 35 | |
| 36 void deita__sqlite_connection_close(Deita_Connection *p_connection) | |
| 37 { | |
| 38 if (!p_connection) | |
| 39 return; | |
| 40 | |
| 41 if (p_connection->native_handle) | |
| 42 { | |
| 43 sqlite3 *p_db = (sqlite3*)p_connection->native_handle; | |
| 44 sqlite3_close(p_db); | |
| 45 p_connection->native_handle = NULL; | |
| 46 } | |
| 47 | |
| 48 p_connection->is_open = FALSE; | |
| 49 free(p_connection); | |
| 50 } | |
| 51 | |
| 52 boolean deita__sqlite_connection_is_open(Deita_Connection *p_connection) | |
| 53 { | |
| 54 if (!p_connection) | |
| 55 return FALSE; | |
| 56 | |
| 57 return p_connection->is_open; | |
| 58 } | |
| 59 | |
| 60 Deita_Result_Set* deita__sqlite_query_execute( | |
| 61 Deita_Connection *p_connection, | |
| 62 const char *query, | |
| 63 Dowa_Arena *p_arena) | |
| 64 { | |
| 65 if (!p_connection || !p_connection->native_handle || !query) | |
| 66 return NULL; | |
| 67 | |
| 68 sqlite3 *p_db = (sqlite3*)p_connection->native_handle; | |
| 69 sqlite3_stmt *p_stmt = NULL; | |
| 70 | |
| 71 int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL); | |
| 72 if (result != SQLITE_OK) | |
| 73 { | |
| 74 fprintf(stderr, "deita__sqlite_query_execute: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db)); | |
| 75 return NULL; | |
| 76 } | |
| 77 | |
| 78 Deita_Result_Set *p_result_set = (Deita_Result_Set*)Dowa_Arena_Allocate(p_arena, sizeof(Deita_Result_Set)); | |
| 79 if (!p_result_set) | |
| 80 { | |
| 81 fprintf(stderr, "deita__sqlite_query_execute: Failed to allocate result set\n"); | |
| 82 sqlite3_finalize(p_stmt); | |
| 83 return NULL; | |
| 84 } | |
| 85 | |
| 86 p_result_set->database_type = DEITA_DATABASE_TYPE_SQLITE3; | |
| 87 p_result_set->native_result = p_stmt; | |
| 88 p_result_set->column_count = sqlite3_column_count(p_stmt); | |
| 89 p_result_set->has_data = FALSE; | |
| 90 p_result_set->is_done = FALSE; | |
| 91 | |
| 92 return p_result_set; | |
| 93 } | |
| 94 | |
| 95 Deita_Result_Set* deita__sqlite_query_execute_prepared( | |
| 96 Deita_Connection *p_connection, | |
| 97 const char *query, | |
| 98 int32 parameter_count, | |
| 99 const char **parameter_values, | |
| 100 Dowa_Arena *p_arena) | |
| 101 { | |
| 102 if (!p_connection || !p_connection->native_handle || !query) | |
| 103 return NULL; | |
| 104 | |
| 105 sqlite3 *p_db = (sqlite3*)p_connection->native_handle; | |
| 106 sqlite3_stmt *p_stmt = NULL; | |
| 107 | |
| 108 int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL); | |
| 109 if (result != SQLITE_OK) | |
| 110 { | |
| 111 fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db)); | |
| 112 return NULL; | |
| 113 } | |
| 114 | |
| 115 for (int32 i = 0; i < parameter_count; i++) | |
| 116 { | |
| 117 result = sqlite3_bind_text(p_stmt, i + 1, parameter_values[i], -1, SQLITE_TRANSIENT); | |
| 118 if (result != SQLITE_OK) | |
| 119 { | |
| 120 fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to bind parameter %d: %s\n", i, sqlite3_errmsg(p_db)); | |
| 121 sqlite3_finalize(p_stmt); | |
| 122 return NULL; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 Deita_Result_Set *p_result_set = (Deita_Result_Set*)Dowa_Arena_Allocate(p_arena, sizeof(Deita_Result_Set)); | |
| 127 if (!p_result_set) | |
| 128 { | |
| 129 fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to allocate result set\n"); | |
| 130 sqlite3_finalize(p_stmt); | |
| 131 return NULL; | |
| 132 } | |
| 133 | |
| 134 p_result_set->database_type = DEITA_DATABASE_TYPE_SQLITE3; | |
| 135 p_result_set->native_result = p_stmt; | |
| 136 p_result_set->column_count = sqlite3_column_count(p_stmt); | |
| 137 p_result_set->has_data = FALSE; | |
| 138 p_result_set->is_done = FALSE; | |
| 139 | |
| 140 return p_result_set; | |
| 141 } | |
| 142 | |
| 143 int32 deita__sqlite_query_execute_update( | |
| 144 Deita_Connection *p_connection, | |
| 145 const char *query) | |
| 146 { | |
| 147 if (!p_connection || !p_connection->native_handle || !query) | |
| 148 return -1; | |
| 149 | |
| 150 sqlite3 *p_db = (sqlite3*)p_connection->native_handle; | |
| 151 char *error_message = NULL; | |
| 152 | |
| 153 int32 result = sqlite3_exec(p_db, query, NULL, NULL, &error_message); | |
| 154 if (result != SQLITE_OK) | |
| 155 { | |
| 156 fprintf(stderr, "deita__sqlite_query_execute_update: Failed to execute: %s\n", error_message); | |
| 157 sqlite3_free(error_message); | |
| 158 return -1; | |
| 159 } | |
| 160 | |
| 161 return sqlite3_changes(p_db); | |
| 162 } | |
| 163 | |
| 164 int32 deita__sqlite_query_execute_update_prepared( | |
| 165 Deita_Connection *p_connection, | |
| 166 const char *query, | |
| 167 int32 parameter_count, | |
| 168 const char **parameter_values) | |
| 169 { | |
| 170 if (!p_connection || !p_connection->native_handle || !query) | |
| 171 return -1; | |
| 172 | |
| 173 sqlite3 *p_db = (sqlite3*)p_connection->native_handle; | |
| 174 sqlite3_stmt *p_stmt = NULL; | |
| 175 | |
| 176 int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL); | |
| 177 if (result != SQLITE_OK) | |
| 178 { | |
| 179 fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db)); | |
| 180 return -1; | |
| 181 } | |
| 182 | |
| 183 for (int32 i = 0; i < parameter_count; i++) | |
| 184 { | |
| 185 result = sqlite3_bind_text(p_stmt, i + 1, parameter_values[i], -1, SQLITE_TRANSIENT); | |
| 186 if (result != SQLITE_OK) | |
| 187 { | |
| 188 fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to bind parameter %d: %s\n", i, sqlite3_errmsg(p_db)); | |
| 189 sqlite3_finalize(p_stmt); | |
| 190 return -1; | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 result = sqlite3_step(p_stmt); | |
| 195 if (result != SQLITE_DONE) | |
| 196 { | |
| 197 fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to execute: %s\n", sqlite3_errmsg(p_db)); | |
| 198 sqlite3_finalize(p_stmt); | |
| 199 return -1; | |
| 200 } | |
| 201 | |
| 202 int32 changes = sqlite3_changes(p_db); | |
| 203 sqlite3_finalize(p_stmt); | |
| 204 | |
| 205 return changes; | |
| 206 } | |
| 207 | |
| 208 boolean deita__sqlite_result_set_next(Deita_Result_Set *p_result_set) | |
| 209 { | |
| 210 if (!p_result_set || !p_result_set->native_result || p_result_set->is_done) | |
| 211 return FALSE; | |
| 212 | |
| 213 sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; | |
| 214 int32 result = sqlite3_step(p_stmt); | |
| 215 | |
| 216 if (result == SQLITE_ROW) | |
| 217 { | |
| 218 p_result_set->has_data = TRUE; | |
| 219 return TRUE; | |
| 220 } | |
| 221 else if (result == SQLITE_DONE) | |
| 222 { | |
| 223 p_result_set->has_data = FALSE; | |
| 224 p_result_set->is_done = TRUE; | |
| 225 return FALSE; | |
| 226 } | |
| 227 else | |
| 228 { | |
| 229 fprintf(stderr, "deita__sqlite_result_set_next: Error stepping through results\n"); | |
| 230 p_result_set->has_data = FALSE; | |
| 231 p_result_set->is_done = TRUE; | |
| 232 return FALSE; | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 int32 deita__sqlite_result_set_get_column_count(Deita_Result_Set *p_result_set) | |
| 237 { | |
| 238 if (!p_result_set) | |
| 239 return 0; | |
| 240 | |
| 241 return p_result_set->column_count; | |
| 242 } | |
| 243 | |
| 244 const char* deita__sqlite_result_set_get_column_name( | |
| 245 Deita_Result_Set *p_result_set, | |
| 246 int32 column_index) | |
| 247 { | |
| 248 if (!p_result_set || !p_result_set->native_result) | |
| 249 return NULL; | |
| 250 | |
| 251 sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; | |
| 252 return sqlite3_column_name(p_stmt, column_index); | |
| 253 } | |
| 254 | |
| 255 Deita_Column_Type deita__sqlite_result_set_get_column_type( | |
| 256 Deita_Result_Set *p_result_set, | |
| 257 int32 column_index) | |
| 258 { | |
| 259 if (!p_result_set || !p_result_set->native_result) | |
| 260 return DEITA_COLUMN_TYPE_NULL; | |
| 261 | |
| 262 sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; | |
| 263 int32 sqlite_type = sqlite3_column_type(p_stmt, column_index); | |
| 264 | |
| 265 switch (sqlite_type) | |
| 266 { | |
| 267 case SQLITE_INTEGER: | |
| 268 return DEITA_COLUMN_TYPE_INTEGER; | |
| 269 case SQLITE_FLOAT: | |
| 270 return DEITA_COLUMN_TYPE_REAL; | |
| 271 case SQLITE_TEXT: | |
| 272 return DEITA_COLUMN_TYPE_TEXT; | |
| 273 case SQLITE_BLOB: | |
| 274 return DEITA_COLUMN_TYPE_BLOB; | |
| 275 case SQLITE_NULL: | |
| 276 default: | |
| 277 return DEITA_COLUMN_TYPE_NULL; | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 const char* deita__sqlite_result_set_get_text( | |
| 282 Deita_Result_Set *p_result_set, | |
| 283 int32 column_index) | |
| 284 { | |
| 285 if (!p_result_set || !p_result_set->native_result) | |
| 286 return NULL; | |
| 287 | |
| 288 sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; | |
| 289 const unsigned char *text = sqlite3_column_text(p_stmt, column_index); | |
| 290 | |
| 291 return (const char*)text; | |
| 292 } | |
| 293 | |
| 294 int64 deita__sqlite_result_set_get_integer( | |
| 295 Deita_Result_Set *p_result_set, | |
| 296 int32 column_index) | |
| 297 { | |
| 298 if (!p_result_set || !p_result_set->native_result) | |
| 299 return 0; | |
| 300 | |
| 301 sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; | |
| 302 return sqlite3_column_int64(p_stmt, column_index); | |
| 303 } | |
| 304 | |
| 305 double deita__sqlite_result_set_get_real( | |
| 306 Deita_Result_Set *p_result_set, | |
| 307 int32 column_index) | |
| 308 { | |
| 309 if (!p_result_set || !p_result_set->native_result) | |
| 310 return 0.0; | |
| 311 | |
| 312 sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; | |
| 313 return sqlite3_column_double(p_stmt, column_index); | |
| 314 } | |
| 315 | |
| 316 void deita__sqlite_result_set_free(Deita_Result_Set *p_result_set) | |
| 317 { | |
| 318 if (!p_result_set) | |
| 319 return; | |
| 320 | |
| 321 if (p_result_set->native_result) | |
| 322 { | |
| 323 sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result; | |
| 324 sqlite3_finalize(p_stmt); | |
| 325 p_result_set->native_result = NULL; | |
| 326 } | |
| 327 } |