GCC Code Coverage Report


Directory: src/gate/
File: src/gate/data/sqlite3_adapter.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 169 357 47.3%
Functions: 15 23 65.2%
Branches: 34 161 21.1%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/data/sqlite3_adapter.h"
29 #include "gate/results.h"
30 #include "gate/arrays.h"
31 #include "gate/debugging.h"
32 #include "gate/data/adapter_base.h"
33
34 #if defined(GATE_EXTLIB_SQLITE3)
35 # define GATE_DATA_SQLITE3_LIB_IMPL 1
36 #else
37 # if defined(GATE_SYS_WIN) || defined(GATE_SYS_POSIX)
38 # if !defined(GATE_DATA_SQLITE3_SHAREDLIB)
39 # define GATE_DATA_SQLITE3_SHAREDLIB 1
40 # endif
41 # define GATE_DATA_SQLITE3_LIB_IMPL 1
42 # else
43 # define GATE_DATA_SQLITE3_NO_IMPL 1
44 # endif
45 #endif
46
47
48 #if defined(GATE_DATA_SQLITE3_LIB_IMPL)
49
50
51 #if !defined(GATE_DATA_SQLITE3_SHAREDLIB)
52
53 # include "sqlite3.h"
54
55 #else
56
57 # include "gate/libraries.h"
58
59 typedef struct gate_sqlite3_stmt_impl sqlite3_stmt;
60 typedef struct gate_sqlite3_impl sqlite3;
61 typedef gate_int64_t sqlite_int64;
62
63 #define SQLITE_INTEGER 1
64 #define SQLITE_FLOAT 2
65 #define SQLITE_BLOB 4
66 #define SQLITE_NULL 5
67 #ifdef SQLITE_TEXT
68 # undef SQLITE_TEXT
69 #else
70 # define SQLITE_TEXT 3
71 #endif
72 #define SQLITE3_TEXT 3
73
74 #define SQLITE_OK 0
75 #define SQLITE_ERROR 1
76 #define SQLITE_INTERNAL 2
77 #define SQLITE_PERM 3
78 #define SQLITE_ABORT 4
79 #define SQLITE_BUSY 5
80 #define SQLITE_LOCKED 6
81 #define SQLITE_NOMEM 7
82 #define SQLITE_READONLY 8
83 #define SQLITE_INTERRUPT 9
84 #define SQLITE_IOERR 10
85 #define SQLITE_CORRUPT 11
86 #define SQLITE_NOTFOUND 12
87 #define SQLITE_FULL 13
88 #define SQLITE_CANTOPEN 14
89 #define SQLITE_PROTOCOL 15
90 #define SQLITE_EMPTY 16
91 #define SQLITE_SCHEMA 17
92 #define SQLITE_TOOBIG 18
93 #define SQLITE_CONSTRAINT 19
94 #define SQLITE_MISMATCH 20
95 #define SQLITE_MISUSE 21
96 #define SQLITE_NOLFS 22
97 #define SQLITE_AUTH 23
98 #define SQLITE_FORMAT 24
99 #define SQLITE_RANGE 25
100 #define SQLITE_NOTADB 26
101 #define SQLITE_NOTICE 27
102 #define SQLITE_WARNING 28
103 #define SQLITE_ROW 100
104 #define SQLITE_DONE 101
105
106 #define SQLITE_OPEN_READONLY 0x00000001
107 #define SQLITE_OPEN_READWRITE 0x00000002
108 #define SQLITE_OPEN_CREATE 0x00000004
109 #define SQLITE_OPEN_DELETEONCLOSE 0x00000008
110 #define SQLITE_OPEN_EXCLUSIVE 0x00000010
111 #define SQLITE_OPEN_AUTOPROXY 0x00000020
112 #define SQLITE_OPEN_URI 0x00000040
113 #define SQLITE_OPEN_MEMORY 0x00000080
114 #define SQLITE_OPEN_MAIN_DB 0x00000100
115 #define SQLITE_OPEN_TEMP_DB 0x00000200
116 #define SQLITE_OPEN_TRANSIENT_DB 0x00000400
117 #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800
118 #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000
119 #define SQLITE_OPEN_SUBJOURNAL 0x00002000
120 #define SQLITE_OPEN_SUPER_JOURNAL 0x00004000
121 #define SQLITE_OPEN_NOMUTEX 0x00008000
122 #define SQLITE_OPEN_FULLMUTEX 0x00010000
123 #define SQLITE_OPEN_SHAREDCACHE 0x00020000
124 #define SQLITE_OPEN_PRIVATECACHE 0x00040000
125 #define SQLITE_OPEN_WAL 0x00080000
126 #define SQLITE_OPEN_NOFOLLOW 0x01000000
127 #define SQLITE_OPEN_EXRESCODE 0x02000000
128
129 #endif
130
131 typedef struct gate_sqlite3_api_class
132 {
133 int (*column_type) (sqlite3_stmt* pStmt, int i);
134 int (*column_count) (sqlite3_stmt* pStmt);
135 const char* (*column_name) (sqlite3_stmt* pStmt, int N);
136 sqlite_int64 (*column_int64) (sqlite3_stmt* pStmt, int i);
137 double (*column_double) (sqlite3_stmt* pStmt, int i);
138 int (*column_bytes) (sqlite3_stmt* pStmt, int i);
139 const void* (*column_blob) (sqlite3_stmt* pStmt, int i);
140 const unsigned char*(*column_text) (sqlite3_stmt* pStmt, int i);
141
142 int (*bind_parameter_count) (sqlite3_stmt* pStmt);
143 int (*bind_parameter_index) (sqlite3_stmt* pStmt, const char* zName);
144 const char* (*bind_parameter_name) (sqlite3_stmt* pStmt, int i);
145 int (*bind_blob) (sqlite3_stmt* pStmt, int i, const void* value, int len, void(*dtor)(void*));
146 int (*bind_double) (sqlite3_stmt* pStmt, int i, double value);
147 int (*bind_int64) (sqlite3_stmt* pStmt, int i, sqlite_int64 value);
148 int (*bind_null) (sqlite3_stmt* pStmt, int i);
149 int (*bind_text) (sqlite3_stmt* pStmt, int i, const char* text, int len, void(*dtor)(void*));
150
151 int (*prepare) (sqlite3* db, const char* zSql, int nBytes, sqlite3_stmt** ppStmt, const char** pzTail);
152 int (*clear_bindings) (sqlite3_stmt*);
153 int (*reset) (sqlite3_stmt* pStmt);
154 int (*changes) (sqlite3* db);
155 int (*close) (sqlite3* db);
156 int (*open) (const char* zFilename, sqlite3** ppDb);
157 int (*open_v2) (const char* zFilename, sqlite3** ppDb, int flags, const char* zVfs);
158 int (*finalize) (sqlite3_stmt* pStmt);
159 int (*step) (sqlite3_stmt* pStmt);
160 const char* (*errmsg) (sqlite3* db);
161 } gate_sqlite3_api_t;
162
163 static gate_sqlite3_api_t sqlite3_api = GATE_INIT_EMPTY;
164
165
166 #if !defined(GATE_DATA_SQLITE3_SHAREDLIB)
167
168 #if defined(GATE_DEBUG_MODE)
169 # /* define GATE_DATA_SQLITE3_DEBUGGING 1 */
170 #endif
171
172 #if defined(GATE_DATA_SQLITE3_DEBUGGING)
173 void errorLogCallback(void* pArg, int iErrCode, const char* zMsg)
174 {
175 printf("SQLITE (%d): %s\n", iErrCode, zMsg);
176 }
177 #endif
178
179 1 static gate_result_t gate_data_sqlite3_api_init()
180 {
181 static gate_atomic_flag_t sqlite3_api_initialized = GATE_ATOMIC_FLAG_INIT;
182
183
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (gate_atomic_flag_set(&sqlite3_api_initialized) == 0)
184 {
185 1 sqlite3_api.column_type = &sqlite3_column_type;
186 1 sqlite3_api.column_count = &sqlite3_column_count;
187 1 sqlite3_api.column_name = &sqlite3_column_name;
188 1 sqlite3_api.column_int64 = &sqlite3_column_int64;
189 1 sqlite3_api.column_double = &sqlite3_column_double;
190 1 sqlite3_api.column_bytes = &sqlite3_column_bytes;
191 1 sqlite3_api.column_blob = &sqlite3_column_blob;
192 1 sqlite3_api.column_text = &sqlite3_column_text;
193
194 1 sqlite3_api.bind_parameter_count = &sqlite3_bind_parameter_count;
195 1 sqlite3_api.bind_parameter_index = &sqlite3_bind_parameter_index;
196 1 sqlite3_api.bind_parameter_name = &sqlite3_bind_parameter_name;
197 1 sqlite3_api.bind_blob = &sqlite3_bind_blob;
198 1 sqlite3_api.bind_double = &sqlite3_bind_double;
199 1 sqlite3_api.bind_int64 = &sqlite3_bind_int64;
200 1 sqlite3_api.bind_null = &sqlite3_bind_null;
201 1 sqlite3_api.bind_text = &sqlite3_bind_text;
202
203 1 sqlite3_api.prepare = &sqlite3_prepare;
204 1 sqlite3_api.clear_bindings = &sqlite3_clear_bindings;
205 1 sqlite3_api.reset = &sqlite3_reset;
206 1 sqlite3_api.changes = &sqlite3_changes;
207 1 sqlite3_api.close = &sqlite3_close;
208 1 sqlite3_api.open = &sqlite3_open;
209 1 sqlite3_api.open_v2 = &sqlite3_open_v2;
210 1 sqlite3_api.finalize = &sqlite3_finalize;
211 1 sqlite3_api.step = &sqlite3_step;
212 1 sqlite3_api.errmsg = &sqlite3_errmsg;
213 #if defined(GATE_DATA_SQLITE3_DEBUGGING)
214 sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, NULL);
215 #endif
216 }
217 1 return GATE_RESULT_OK;
218 }
219
220 #else
221
222
223 static char const* gate_data_sqlite3_lib_names[] = {
224 #if defined(GATE_SYS_WIN)
225 "sqlite3.dll"
226 #else
227 "libsqlite3.so.0"
228 #endif
229 #if defined(GATE_DATA_SQLITE3_LIB_ALTERNATIVES)
230 ,
231 GATE_DATA_SQLITE3_LIB_ALTERNATIVES
232 #endif
233 };
234
235 static gate_size_t const gate_data_sqlite3_lib_names_count
236 = sizeof(gate_data_sqlite3_lib_names) / sizeof(gate_data_sqlite3_lib_names[0]);
237
238
239 static gate_result_t gate_data_sqlite3_api_load(gate_library_t lib)
240 {
241 #define SQL3_LOAD_FUNC(name, func_ptr) \
242 ret = gate_library_get_function_name(lib, name, func_ptr); \
243 if(GATE_FAILED(ret)) return ret;
244
245 gate_result_t ret;
246 SQL3_LOAD_FUNC("sqlite3_column_type", &sqlite3_api.column_type);
247 SQL3_LOAD_FUNC("sqlite3_column_count", &sqlite3_api.column_count);
248 SQL3_LOAD_FUNC("sqlite3_column_name", &sqlite3_api.column_name);
249 SQL3_LOAD_FUNC("sqlite3_column_int64", &sqlite3_api.column_int64);
250 SQL3_LOAD_FUNC("sqlite3_column_double", &sqlite3_api.column_double);
251 SQL3_LOAD_FUNC("sqlite3_column_bytes", &sqlite3_api.column_bytes);
252 SQL3_LOAD_FUNC("sqlite3_column_blob", &sqlite3_api.column_blob);
253 SQL3_LOAD_FUNC("sqlite3_column_text", &sqlite3_api.column_text);
254
255 SQL3_LOAD_FUNC("sqlite3_bind_parameter_count", &sqlite3_api.bind_parameter_count);
256 SQL3_LOAD_FUNC("sqlite3_bind_parameter_index", &sqlite3_api.bind_parameter_index);
257 SQL3_LOAD_FUNC("sqlite3_bind_parameter_name", &sqlite3_api.bind_parameter_name);
258 SQL3_LOAD_FUNC("sqlite3_bind_blob", &sqlite3_api.bind_blob);
259 SQL3_LOAD_FUNC("sqlite3_bind_double", &sqlite3_api.bind_double);
260 SQL3_LOAD_FUNC("sqlite3_bind_int64", &sqlite3_api.bind_int64);
261 SQL3_LOAD_FUNC("sqlite3_bind_null", &sqlite3_api.bind_null);
262 SQL3_LOAD_FUNC("sqlite3_bind_text", &sqlite3_api.bind_text);
263
264 SQL3_LOAD_FUNC("sqlite3_prepare", &sqlite3_api.prepare);
265 SQL3_LOAD_FUNC("sqlite3_clear_bindings", &sqlite3_api.clear_bindings);
266 SQL3_LOAD_FUNC("sqlite3_reset", &sqlite3_api.reset);
267 SQL3_LOAD_FUNC("sqlite3_changes", &sqlite3_api.changes);
268 SQL3_LOAD_FUNC("sqlite3_close", &sqlite3_api.close);
269 SQL3_LOAD_FUNC("sqlite3_open", &sqlite3_api.open);
270 SQL3_LOAD_FUNC("sqlite3_open_v2", &sqlite3_api.open_v2);
271 SQL3_LOAD_FUNC("sqlite3_finalize", &sqlite3_api.finalize);
272 SQL3_LOAD_FUNC("sqlite3_step", &sqlite3_api.step);
273 SQL3_LOAD_FUNC("sqlite3_errmsg", &sqlite3_api.errmsg);
274 return GATE_RESULT_OK;
275 }
276
277 static gate_result_t gate_data_sqlite3_api_init()
278 {
279 static gate_atomic_flag_t sqlite3_api_initialized = GATE_ATOMIC_FLAG_INIT;
280 gate_string_t libname = GATE_STRING_INIT_EMPTY;
281 gate_size_t index;
282 gate_library_t lib = NULL;
283 gate_result_t result;
284
285 if (gate_atomic_flag_set(&sqlite3_api_initialized) == true)
286 {
287 /* already loaded */
288 return GATE_RESULT_OK;
289 }
290
291 for (index = 0; index != gate_data_sqlite3_lib_names_count; ++index)
292 {
293 gate_string_create_static(&libname, gate_data_sqlite3_lib_names[index]);
294 result = gate_library_open(&libname, &lib, GATE_LIBRARY_FLAG_DEFAULT);
295 if (GATE_FAILED(result))
296 {
297 continue;
298 }
299 result = gate_data_sqlite3_api_load(lib);
300 if (GATE_SUCCEEDED(result))
301 {
302 /* library loaded -> OK */
303 return GATE_RESULT_OK;
304 }
305 gate_library_close(lib);
306 }
307 /* no library loaded -> reset */
308 gate_atomic_flag_clear(&sqlite3_api_initialized);
309 return GATE_RESULT_NOTAVAILABLE;
310 }
311
312 #endif
313
314
315 static gate_result_t sqlite3_error_to_gate_result(int sql3_error)
316 {
317 switch (sql3_error)
318 {
319 case SQLITE_OK: return GATE_RESULT_OK;
320 case SQLITE_ROW: return GATE_RESULT_OK_PARTIAL;
321 case SQLITE_ERROR: return GATE_RESULT_FAILED;
322 case SQLITE_INTERNAL: return GATE_RESULT_UNKNOWNERROR;
323 case SQLITE_PERM: return GATE_RESULT_PERMISSIONDENIED;
324 case SQLITE_ABORT: return GATE_RESULT_CANCELED;
325 case SQLITE_BUSY: return GATE_RESULT_BLOCKED;
326 case SQLITE_LOCKED: return GATE_RESULT_LOCKED;
327 case SQLITE_NOMEM: return GATE_RESULT_OUTOFMEMORY;
328 case SQLITE_READONLY: return GATE_RESULT_ACCESSDENIED;
329 case SQLITE_INTERRUPT: return GATE_RESULT_EXECUTIONINTERRUPTED;
330 case SQLITE_IOERR: return GATE_RESULT_DEVICEERROR;
331 case SQLITE_CORRUPT: return GATE_RESULT_INVALIDDATA;
332 case SQLITE_NOTFOUND: return GATE_RESULT_INVALIDARG;
333 case SQLITE_FULL: return GATE_RESULT_OUTOFRESOURCES;
334 case SQLITE_CANTOPEN: return GATE_RESULT_NOTAVAILABLE;
335 case SQLITE_PROTOCOL: return GATE_RESULT_NOTREADY;
336 case SQLITE_SCHEMA: return GATE_RESULT_PRECONDITIONFAILED;
337 case SQLITE_TOOBIG: return GATE_RESULT_OVERFLOW;
338 case SQLITE_CONSTRAINT: return GATE_RESULT_EXECUTIONFAILED;
339 case SQLITE_MISMATCH: return GATE_RESULT_INCORRECTTYPE;
340 case SQLITE_MISUSE: return GATE_RESULT_INVALIDSTATE;
341 case SQLITE_NOLFS: return GATE_RESULT_NOTSUPPORTED;
342 case SQLITE_AUTH: return GATE_RESULT_SECURITYBREACH;
343 case SQLITE_RANGE: return GATE_RESULT_OUTOFBOUNDS;
344 case SQLITE_NOTADB: return GATE_RESULT_INVALIDCONTENT;
345 case SQLITE_DONE: return GATE_RESULT_ENDOFSTREAM;
346 default: return GATE_RESULT_FAILED;
347 }
348 }
349
350 4 static gate_bool_t gate_data_reader_sqlite3_is_valid(gate_data_reader_base_t* reader)
351 {
352 4 sqlite3_stmt* stmt = (sqlite3_stmt*)reader->native_handles[0];
353 4 return stmt != NULL;
354 }
355
356 3 static gate_result_t gate_data_reader_sqlite3_close(gate_data_reader_base_t* reader)
357 {
358 3 gate_result_t ret = GATE_RESULT_OK;
359 3 sqlite3_stmt* stmt = (sqlite3_stmt*)reader->native_handles[0];
360
361 do
362 {
363 3 gate_mem_clear(reader->native_handles, sizeof(reader->native_handles));
364 3 ret = GATE_RESULT_OK;
365 } while (0);
366 3 return ret;
367 }
368
369 2 static gate_result_t gate_data_reader_sqlite3_next(gate_data_reader_base_t* reader)
370 {
371 2 gate_result_t ret = GATE_RESULT_FAILED;
372 2 sqlite3_stmt* stmt = (sqlite3_stmt*)reader->native_handles[0];
373 int sql3_result;
374 gate_size_t ndx;
375 int sql3_type;
376 gate_int64_t i64;
377 gate_real64_t r64;
378 gate_value_t* ptr_value;
379 int byte_count;
380 gate_uint8_t const* byte_ptr;
381 char const* text_ptr;
382 2 gate_arraylist_t arraylist = NULL;
383 2 gate_array_t arr = GATE_INIT_EMPTY;
384 2 gate_string_t str = GATE_STRING_INIT_EMPTY;
385
386 do
387 {
388
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!gate_data_reader_base_is_valid(reader))
389 {
390 ret = GATE_RESULT_ENDOFSTREAM;
391 break;
392 }
393
394 2 sql3_result = sqlite3_api.step(stmt);
395
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (SQLITE_DONE == sql3_result)
396 {
397 /* end of data stream reached */
398 1 ret = GATE_RESULT_ENDOFSTREAM;
399 1 gate_data_reader_base_close(reader);
400 1 break;
401 }
402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (SQLITE_ROW != sql3_result)
403 {
404 /* data read error occured */
405 ret = GATE_RESULT_FAILED;
406 GATE_DEBUG_TRACE_MSG_VALUE("sqlite3_step() failed", sql3_result);
407 break;
408 }
409
410 /* succeeded: */
411
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (ndx = 0; ndx != reader->field_count; ++ndx)
412 {
413 1 ptr_value = &reader->values[ndx];
414 1 gate_value_release(ptr_value);
415
416 1 sql3_type = sqlite3_api.column_type(stmt, (int)ndx);
417
1/5
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 switch (sql3_type)
418 {
419 case SQLITE_INTEGER:
420 i64 = (gate_int64_t)sqlite3_api.column_int64(stmt, (int)ndx);
421 gate_value_create(GATE_TYPE_I64, &i64, ptr_value);
422 break;
423 case SQLITE_FLOAT:
424 r64 = (gate_real64_t)sqlite3_api.column_double(stmt, (int)ndx);
425 gate_value_create(GATE_TYPE_R64, &r64, ptr_value);
426 break;
427 case SQLITE_BLOB:
428 byte_count = sqlite3_api.column_bytes(stmt, (int)ndx);
429 byte_ptr = (gate_uint8_t const*)sqlite3_api.column_blob(stmt, (int)ndx);
430 arraylist = gate_arraylist_create(1, byte_ptr, (gate_size_t)byte_count, NULL, NULL);
431 gate_array_create(&arr, arraylist);
432 gate_value_create(GATE_TYPE_ARRAY, &arr, ptr_value);
433 gate_array_release(&arr);
434 break;
435 1 case SQLITE_TEXT:
436 1 byte_count = sqlite3_api.column_bytes(stmt, (int)ndx);
437 1 text_ptr = (char const*)sqlite3_api.column_text(stmt, (int)ndx);
438 1 gate_string_create(&str, text_ptr, (gate_size_t)byte_count);
439 1 gate_value_create(GATE_TYPE_STRING, &str, ptr_value);
440 1 gate_string_release(&str);
441 1 break;
442 default:
443 case SQLITE_NULL:
444 /* already released */
445 break;
446 }
447 }
448 1 ret = GATE_RESULT_OK;
449
450 } while (0);
451
452 2 return ret;
453 }
454
455
456 1 static gate_result_t gate_data_reader_sqlite3_init(gate_data_reader_base_t* reader)
457 {
458 1 gate_result_t ret = GATE_RESULT_OK;
459 1 sqlite3_stmt* stmt = (sqlite3_stmt*)reader->native_handles[0];
460 gate_size_t ndx;
461 char const* ptr_name;
462
463 1 reader->field_count = (gate_size_t)sqlite3_api.column_count(stmt);
464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (reader->field_count > sizeof(reader->names) / sizeof(reader->names[0]))
465 {
466 reader->field_count = sizeof(reader->names) / sizeof(reader->names[0]);
467 }
468
469
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (ndx = 0; ndx != reader->field_count; ++ndx)
470 {
471 1 ptr_name = sqlite3_api.column_name(stmt, (int)ndx);
472 1 gate_string_create(&reader->names[ndx], ptr_name, gate_str_length(ptr_name));
473 }
474
475 1 return ret;
476 }
477
478
479 1 static gate_result_t sqlite3_execute_statement(sqlite3* db, sqlite3_stmt* stmt, gate_int32_t* affected_rows)
480 {
481 1 int sql3_result = 0;
482
483 do
484 {
485 1 sql3_result = sqlite3_api.step(stmt);
486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } while (sql3_result == SQLITE_ROW);
487
488
1/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 switch (sql3_result)
489 {
490 1 case SQLITE_DONE:
491 {
492
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (affected_rows != NULL)
493 {
494 1 *affected_rows = (gate_int32_t)sqlite3_api.changes(db);
495 }
496 1 return GATE_RESULT_OK;
497 }
498 case SQLITE_BUSY:
499 {
500 GATE_DEBUG_TRACE("sqlite DB is busy");
501 return GATE_RESULT_LOCKED;
502 }
503 case SQLITE_ERROR:
504 {
505 GATE_DEBUG_TRACE(sqlite3_api.errmsg(db));
506 return GATE_RESULT_FAILED;
507 }
508 default:
509 {
510 GATE_DEBUG_TRACE_MSG_VALUE("Unknown sqlite3_step() result", sql3_result);
511 return GATE_RESULT_UNKNOWNERROR;
512 }
513 }
514 }
515
516
517 1 static gate_result_t sqlite3_query_statement(gate_data_statement_t* ptr_statement, sqlite3_stmt* stmt, gate_data_reader_t** ptr_reader)
518 {
519 1 gate_data_reader_t* reader = NULL;
520 1 gate_data_handles_t handles = GATE_INIT_EMPTY;
521
522 1 handles[0] = (void*)stmt;
523
524 1 reader = gate_data_reader_base_create(
525 ptr_statement, handles,
526 &gate_data_reader_sqlite3_init,
527 &gate_data_reader_sqlite3_is_valid,
528 &gate_data_reader_sqlite3_next,
529 &gate_data_reader_sqlite3_close);
530
531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (reader == NULL)
532 {
533 return GATE_RESULT_OUTOFMEMORY;
534 }
535
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_reader)
536 {
537 1 *ptr_reader = reader;
538 1 reader = NULL;
539 }
540 else
541 {
542 gate_object_release(reader);
543 }
544
545 1 return GATE_RESULT_OK;
546 }
547
548
549 2 static gate_result_t sqlite3stmt_init(gate_data_statement_base_t* impl)
550 {
551 2 gate_result_t ret = GATE_RESULT_FAILED;
552 2 gate_string_t cmd = GATE_STRING_INIT_EMPTY;
553 2 sqlite3* db = impl->native_handles[0];
554 2 sqlite3_stmt* stmt = impl->native_handles[1];
555 int cnt;
556
557 do
558 {
559 2 cnt = sqlite3_api.bind_parameter_count(stmt);
560
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (cnt >= 0)
561 {
562 2 impl->param_count = (gate_size_t)cnt;
563 }
564 2 ret = GATE_RESULT_OK;
565 } while (0);
566
567 2 return ret;
568 }
569
570 2 static void sqlite3stmt_close(gate_data_statement_base_t* impl)
571 {
572 2 sqlite3_stmt* sql3_statement = (sqlite3_stmt*)impl->native_handles[1];
573 2 impl->native_handles[1] = NULL;
574
575
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (sql3_statement != NULL)
576 {
577 2 sqlite3_api.finalize(sql3_statement);
578 }
579 2 }
580
581 static gate_result_t sql3_bind_int(sqlite3_stmt* stmt, int index, gate_int64_t value)
582 {
583 int sql3_result = sqlite3_api.bind_int64(stmt, index, value);
584 return sqlite3_error_to_gate_result(sql3_result);
585 }
586
587 static gate_result_t sql3_bind_real(sqlite3_stmt* stmt, int index, gate_real64_t value)
588 {
589 int sql3_result = sqlite3_api.bind_double(stmt, index, value);
590 return sqlite3_error_to_gate_result(sql3_result);
591 }
592
593 static gate_result_t sql3_bind_blob(sqlite3_stmt* stmt, int index, void const* data, gate_size_t len)
594 {
595 int sql3_result;
596 char* buffer = NULL;
597
598 if ((len == 0) || (data == NULL))
599 {
600 sql3_result = sqlite3_api.bind_blob(stmt, index, NULL, 0, NULL);
601 }
602 else
603 {
604 buffer = gate_mem_alloc(len);
605 if (buffer == NULL)
606 {
607 return GATE_RESULT_OUTOFMEMORY;
608 }
609 gate_mem_copy(buffer, data, len);
610 sql3_result = sqlite3_api.bind_blob(stmt, index, buffer, (int)len, &gate_mem_dealloc);
611 if (sql3_result != SQLITE_OK)
612 {
613 gate_mem_dealloc(buffer);
614 }
615 }
616 return sqlite3_error_to_gate_result(sql3_result);
617 }
618
619 static gate_result_t sql3_bind_text(sqlite3_stmt* stmt, int index, char const* text, gate_size_t len)
620 {
621 int sql3_result;
622 char* buffer = NULL;
623
624 if ((len == 0) || (text == NULL))
625 {
626 sql3_result = sqlite3_api.bind_text(stmt, index, NULL, 0, NULL);
627 }
628 else
629 {
630 buffer = gate_mem_alloc(len + 1);
631 if (buffer == NULL)
632 {
633 return GATE_RESULT_OUTOFMEMORY;
634 }
635 gate_mem_copy(buffer, text, len);
636 buffer[len] = 0;
637 sql3_result = sqlite3_api.bind_text(stmt, index, buffer, (int)len, &gate_mem_dealloc);
638 if (sql3_result != SQLITE_OK)
639 {
640 gate_mem_dealloc(buffer);
641 }
642 }
643 return sqlite3_error_to_gate_result(sql3_result);
644 }
645
646 static gate_result_t sqlite3stmt_set_param(gate_data_statement_base_t* self, gate_size_t param_index, gate_value_t const* value)
647 {
648 gate_result_t ret = GATE_RESULT_FAILED;
649 sqlite3_stmt* stmt = (sqlite3_stmt*)self->native_handles[1];
650 int param_count;
651 int sql3_result = SQLITE_MISMATCH;
652 int index = (int)param_index;
653 gate_cstrbuffer8_t buffer;
654 gate_size_t len;
655 gate_datetime_t dt = GATE_INIT_EMPTY;
656
657 param_count = sqlite3_api.bind_parameter_count(stmt);
658 if ((index == 0) || (index > param_count))
659 {
660 return GATE_RESULT_OUTOFBOUNDS;
661 }
662
663 if ((value == NULL) || (value->value_type == GATE_TYPE_EMPTY))
664 {
665 sql3_result = sqlite3_api.bind_null(stmt, index);
666 return sqlite3_error_to_gate_result(sql3_result);
667 }
668 else
669 {
670 switch (value->value_type)
671 {
672 case GATE_TYPE_BOOL: return sql3_bind_int(stmt, index, value->content.bool_value);
673 case GATE_TYPE_I8: return sql3_bind_int(stmt, index, value->content.i8_value);
674 case GATE_TYPE_UI8: return sql3_bind_int(stmt, index, value->content.ui8_value);
675 case GATE_TYPE_I16: return sql3_bind_int(stmt, index, value->content.i16_value);
676 case GATE_TYPE_UI16: return sql3_bind_int(stmt, index, value->content.ui16_value);
677 case GATE_TYPE_I32: return sql3_bind_int(stmt, index, value->content.i32_value);
678 case GATE_TYPE_UI32: return sql3_bind_int(stmt, index, value->content.ui32_value);
679 case GATE_TYPE_I64: return sql3_bind_int(stmt, index, value->content.i64_value);
680 case GATE_TYPE_UI64: return sql3_bind_int(stmt, index, value->content.ui64_value);
681
682 case GATE_TYPE_R32: return sql3_bind_real(stmt, index, value->content.r32_value);
683 case GATE_TYPE_R64: return sql3_bind_real(stmt, index, value->content.r64_value);
684
685 case GATE_TYPE_BLOB: return sql3_bind_blob(stmt, index, value->content.blob_value.data, value->content.blob_value.length);
686
687 case GATE_TYPE_CSTR: return sql3_bind_text(stmt, index, value->content.cstring_value, gate_str_length(value->content.cstring_value));
688 case GATE_TYPE_STRING: return sql3_bind_text(stmt, index, value->content.string_value.str, value->content.string_value.length);
689 case GATE_TYPE_WSTR:
690 {
691 if (NULL == gate_cstrbuffer_create_wstr(&buffer, value->content.wstring_value, gate_wstr_length(value->content.wstring_value)))
692 {
693 return GATE_RESULT_OUTOFMEMORY;
694 }
695 ret = sql3_bind_text(stmt, index, gate_cstrbuffer_get(&buffer), gate_cstrbuffer_length(&buffer));
696 gate_cstrbuffer_destroy(&buffer);
697 return ret;
698 }
699 case GATE_TYPE_GUID:
700 {
701 ret = gate_guid_to_string(&value->content.guid_value, buffer.local_buffer);
702 GATE_RETURN_IF_FAILED(ret);
703 return sql3_bind_text(stmt, index, buffer.local_buffer, gate_str_length(buffer.local_buffer));
704 }
705 case GATE_TYPE_DATE:
706 {
707 dt.date = value->content.date_value;
708 len = sizeof(buffer.local_buffer);
709 ret = gate_date_to_string(&dt, 0, "{YYYY}-{MM}-{DD}", buffer.local_buffer, &len);
710 GATE_RETURN_IF_FAILED(ret);
711 return sql3_bind_text(stmt, index, buffer.local_buffer, len);
712 }
713 case GATE_TYPE_DATETIME:
714 {
715 len = sizeof(buffer.local_buffer);
716 ret = gate_date_to_string(&value->content.datetime_value, 0, "{YYYY}-{MM}-{DD} {hh}:{mm}:{ss}", buffer.local_buffer, &len);
717 GATE_RETURN_IF_FAILED(ret);
718 return sql3_bind_text(stmt, index, buffer.local_buffer, len);
719 }
720 case GATE_TYPE_TIME:
721 {
722 ret = gate_time_to_datetime(&value->content.time_value, &dt);
723 GATE_RETURN_IF_FAILED(ret);
724 len = sizeof(buffer.local_buffer);
725 ret = gate_date_to_string(&dt, 0, "{YYYY}-{MM}-{DD} {hh}:{mm}:{ss}", buffer.local_buffer, &len);
726 GATE_RETURN_IF_FAILED(ret);
727 return sql3_bind_text(stmt, index, buffer.local_buffer, len);
728 }
729
730 case GATE_TYPE_PROPERTY:
731 default:
732 return GATE_RESULT_INCORRECTTYPE;
733 }
734 }
735 return ret;
736 }
737 static gate_result_t sqlite3stmt_set_named_param(gate_data_statement_base_t* self, gate_string_t const* name, gate_value_t const* value)
738 {
739 gate_result_t ret = GATE_RESULT_FAILED;
740 sqlite3_stmt* sql3_statement = (sqlite3_stmt*)self->native_handles[1];
741 int param_count;
742 int param_ndx;
743 char const* param_name;
744
745 param_count = sqlite3_api.bind_parameter_count(sql3_statement);
746 for (param_ndx = 1; param_ndx <= param_count; ++param_ndx)
747 {
748 param_name = sqlite3_api.bind_parameter_name(sql3_statement, param_ndx);
749 if (gate_string_equals_str(name, param_name))
750 {
751 /* named parameter found, access it by index */
752 return sqlite3stmt_set_param(self, (gate_size_t)param_ndx, value);
753 }
754 }
755 /* no parameter was found */
756 return GATE_RESULT_NOMATCH;
757 }
758 static gate_result_t sqlite3stmt_reset(gate_data_statement_base_t* self)
759 {
760 sqlite3_stmt* sql3_statement = (sqlite3_stmt*)self->native_handles[1];
761 int sql3_result;
762
763 sql3_result = sqlite3_api.clear_bindings(sql3_statement);
764 if (sql3_result != SQLITE_OK)
765 {
766 return sqlite3_error_to_gate_result(sql3_result);
767 }
768
769 sql3_result = sqlite3_api.reset(sql3_statement);
770 if (sql3_result != SQLITE_OK)
771 {
772 return sqlite3_error_to_gate_result(sql3_result);
773 }
774
775 return GATE_RESULT_OK;
776 }
777 1 static gate_result_t sqlite3stmt_execute(gate_data_statement_base_t* self, gate_int32_t* affected_rows)
778 {
779 1 gate_result_t ret = GATE_RESULT_FAILED;
780 1 sqlite3* db = (sqlite3*)self->native_handles[0];
781 1 sqlite3_stmt* stmt = (sqlite3_stmt*)self->native_handles[1];
782
783 1 return sqlite3_execute_statement(db, stmt, affected_rows);
784 }
785 1 static gate_result_t sqlite3stmt_query(gate_data_statement_base_t* self, gate_data_reader_t** ptr_reader)
786 {
787 1 sqlite3_stmt* sql3_statement = (sqlite3_stmt*)self->native_handles[1];
788 1 return sqlite3_query_statement((gate_data_statement_t*)self, sql3_statement, ptr_reader);
789 }
790
791 2 static gate_result_t gate_data_connection_sqlite3_create_statement(
792 gate_data_connection_base_t* self,
793 gate_string_t const* sql,
794 gate_data_statement_t** ptr_statement)
795 {
796 2 gate_result_t ret = GATE_RESULT_FAILED;
797 gate_data_handles_t handles;
798 2 gate_string_t cmd = GATE_STRING_INIT_EMPTY;
799 2 sqlite3* db = self->native_handles[0];
800 2 sqlite3_stmt* sql3_statement = NULL;
801 int sql3_result;
802 2 gate_data_statement_base_t* ptr_stmt_base = NULL;
803
804 do
805 {
806
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (gate_string_is_empty(sql))
807 {
808 ret = GATE_RESULT_INVALIDARG;
809 break;
810 }
811
812
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (sql->str[sql->length] == '\0')
813 {
814 2 gate_string_duplicate(&cmd, sql);
815 }
816 else
817 {
818 if (NULL == gate_string_create(&cmd, gate_string_ptr(sql, 0), gate_string_length(sql)))
819 {
820 ret = GATE_RESULT_OUTOFMEMORY;
821 break;
822 }
823 }
824
825 2 gate_mem_clear(&handles[0], sizeof(handles));
826
827 2 sql3_result = sqlite3_api.prepare(db, cmd.str, (int)cmd.length, &sql3_statement, NULL);
828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (sql3_result != SQLITE_OK)
829 {
830 ret = GATE_RESULT_FAILED;
831 GATE_DEBUG_TRACE_MSG_VALUE("sqlite3_prepare() failed", sql3_result);
832 break;
833 }
834
835 2 handles[0] = (void*)db;
836 2 handles[1] = (void*)sql3_statement;
837
838 2 ret = gate_data_statement_base_create(
839 self, handles, sql,
840 &sqlite3stmt_init,
841 &sqlite3stmt_close,
842 &sqlite3stmt_set_param,
843 &sqlite3stmt_set_named_param,
844 &sqlite3stmt_reset,
845 &sqlite3stmt_execute,
846 &sqlite3stmt_query,
847 &ptr_stmt_base);
848
849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
850 {
851 sqlite3_api.finalize(sql3_statement);
852 break;
853 }
854
855 /* success case: */
856
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr_statement)
857 {
858 2 *ptr_statement = (gate_data_statement_t*)ptr_stmt_base;
859 2 ptr_stmt_base = NULL;
860 }
861 } while (0);
862
863
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ptr_stmt_base != NULL)
864 {
865 gate_object_release(ptr_stmt_base);
866 ptr_stmt_base = NULL;
867 }
868
869 2 gate_string_release(&cmd);
870 2 return ret;
871 }
872
873
874 1 static gate_result_t gate_data_connection_sqlite3_init(gate_data_connection_base_t* self)
875 {
876 //static gate_string_t const init_commands = GATE_STRING_INIT_STATIC("PRAGMA foreign_keys = ON");
877 //gate_data_connection_execute(self, &init_commands, NULL);
878 1 return GATE_RESULT_OK;
879 }
880
881 1 static void gate_data_connection_sqlite3_close(gate_data_connection_base_t* self)
882 {
883 1 sqlite3* db = (sqlite3*)self->native_handles[0];
884
885
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (db != NULL)
886 {
887 1 sqlite3_api.close(db);
888 }
889 1 gate_mem_clear(self->native_handles, sizeof(self->native_handles));
890 1 }
891
892
893
894 1 gate_result_t gate_data_adapter_sqlite3_create(gate_string_t const* path, gate_enumint_t flags, gate_data_connection_t** ptr_connection)
895 {
896 1 gate_result_t ret = GATE_RESULT_FAILED;
897 char file_path[GATE_MAX_FILEPATH_LENGTH];
898 1 sqlite3* db = NULL;
899 int sql3_result;
900 1 int sql3_flags = 0;
901 1 gate_data_handles_t handles = GATE_INIT_EMPTY;
902
903 do
904 {
905 1 ret = gate_data_sqlite3_api_init();
906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
907
908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FLAG_ENABLED(flags, GATE_DATA_SQLITE3_FLAG_READONLY))
909 {
910 sql3_flags = SQLITE_OPEN_READONLY;
911 }
912 else
913 {
914 1 sql3_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
915 }
916
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 GATE_FLAG_SET(sql3_flags, SQLITE_OPEN_NOMUTEX, !(GATE_FLAG_ENABLED(flags, GATE_DATA_SQLITE3_FLAG_SERIALIZED)));
917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_FLAG_SET(sql3_flags, SQLITE_OPEN_FULLMUTEX, GATE_FLAG_ENABLED(flags, GATE_DATA_SQLITE3_FLAG_SERIALIZED));
918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_FLAG_SET(sql3_flags, SQLITE_OPEN_SHAREDCACHE, GATE_FLAG_ENABLED(flags, GATE_DATA_SQLITE3_FLAG_SHAREDCACHE));
919
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 GATE_FLAG_SET(sql3_flags, SQLITE_OPEN_MEMORY, GATE_FLAG_ENABLED(flags, GATE_DATA_SQLITE3_FLAG_INMEMORY));
920
921 1 gate_string_to_buffer(path, file_path, sizeof(file_path));
922 1 sql3_result = sqlite3_api.open_v2(file_path, &db, sql3_flags, NULL);
923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (sql3_result != SQLITE_OK)
924 {
925 GATE_DEBUG_TRACE_MSG_VALUE("sqlite3_open() failed", sql3_result);
926 ret = GATE_RESULT_FAILED;
927 break;
928 }
929
930 1 handles[0] = (void*)db;
931
932 1 ret = gate_data_connection_base_create(handles,
933 &gate_data_connection_sqlite3_init,
934 &gate_data_connection_sqlite3_close,
935 //&gate_data_connection_sqlite3_execute,
936 //&gate_data_connection_sqlite3_query,
937 &gate_data_connection_sqlite3_create_statement,
938 ptr_connection);
939
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
940
941 1 db = NULL;
942
943 } while (0);
944
945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (db != NULL)
946 {
947 sqlite3_api.close(db);
948 }
949
950 1 return ret;
951 }
952
953 #endif /* GATE_DATA_SQLITE3_LIB_IMPL */
954
955 #if defined(GATE_DATA_SQLITE3_NO_IMPL)
956
957 gate_result_t gate_data_adapter_sqlite3_create(
958 gate_string_t const* path, gate_enumint_t flags,
959 gate_data_connection_t** ptr_connection)
960 {
961 (void)path;
962 (void)flags;
963 (void)ptr_connection;
964 return GATE_RESULT_NOTIMPLEMENTED;
965 }
966
967 #endif /* GATE_DATA_SQLITE3_NO_IMPL */
968
969