GCC Code Coverage Report


Directory: src/gate/
File: src/gate/data/odbc_adapter.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 360 528 68.2%
Functions: 26 29 89.7%
Branches: 106 217 48.8%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, 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/odbc_adapter.h"
29 #include "gate/results.h"
30 #include "gate/libraries.h"
31 #include "gate/arrays.h"
32 #include "gate/debugging.h"
33 #include "gate/guids.h"
34 #include "gate/times.h"
35 #include "gate/data/adapter_base.h"
36
37 #if defined(GATE_DATA_ODBC_ENABLED)
38 # if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WINSTORE) && !defined(GATE_SYS_ANDROID) && !defined(GATE_SYS_DOS) && !defined(GATE_SYS_EFI) && !defined(GATE_SYS_OPENBSD) && !defined(GATE_SYS_WASM) && !defined(GATE_SYS_BEOS)
39 # define GATE_DATA_ODBC_IMPL
40 # endif
41 #endif
42
43
44 #ifdef GATE_DATA_ODBC_IMPL
45
46 #include "gate/platforms.h"
47 #include <sql.h>
48 #include <sqlext.h>
49
50 #if defined(GATE_COMPILER_MSVC98)
51 # ifdef _WIN64
52 typedef INT64 SQLLEN;
53 typedef UINT64 SQLULEN;
54 # else
55 # define SQLLEN SQLINTEGER
56 # define SQLULEN SQLUINTEGER
57 # endif
58 #endif
59
60 typedef struct gate_odbc_functions
61 {
62 SQLRETURN(SQL_API* AllocConnect)(SQLHENV EnvironmentHandle, SQLHDBC* ConnectionHandle);
63 SQLRETURN(SQL_API* FreeEnv)(SQLHENV EnvironmentHandle);
64 SQLRETURN(SQL_API* Connect)(SQLHDBC ConnectionHandle, SQLTCHAR* ServerName, SQLSMALLINT NameLength1,
65 SQLTCHAR* UserName, SQLSMALLINT NameLength2, SQLTCHAR* Authentication, SQLSMALLINT NameLength3);
66 SQLRETURN(SQL_API* FreeConnect)(SQLHDBC ConnectionHandle);
67 SQLRETURN(SQL_API* Disconnect)(SQLHDBC ConnectionHandle);
68 SQLRETURN(SQL_API* AllocStmt)(SQLHDBC ConnectionHandle, SQLHSTMT* StatementHandle);
69 SQLRETURN(SQL_API* Fetch)(SQLHSTMT StatementHandle);
70 SQLRETURN(SQL_API* FreeStmt)(SQLHSTMT StatementHandle, SQLUSMALLINT Option);
71 SQLRETURN(SQL_API* GetData)(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,
72 SQLSMALLINT TargetType, SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN* StrLen_or_Ind);
73 SQLRETURN(SQL_API* DescribeCol)(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLTCHAR* ColumnName,
74 SQLSMALLINT BufferLength, SQLSMALLINT* NameLength, SQLSMALLINT* DataType,
75 SQLULEN* ColumnSize, SQLSMALLINT* DecimalDigits, SQLSMALLINT* Nullable);
76 SQLRETURN(SQL_API* AllocEnv)(SQLHENV* EnvironmentHandle);
77 SQLRETURN(SQL_API* Prepare)(SQLHSTMT StatementHandle, SQLTCHAR* StatementText, SQLINTEGER TextLength);
78 SQLRETURN(SQL_API* Execute)(SQLHSTMT StatementHandle);
79 SQLRETURN(SQL_API* GetDiagRec)(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLTCHAR* Sqlstate,
80 SQLINTEGER* NativeError, SQLTCHAR* MessageText, SQLSMALLINT BufferLength, SQLSMALLINT* TextLength);
81 SQLRETURN(SQL_API* NumResultCols)(SQLHSTMT StatementHandle, SQLSMALLINT* ColumnCount);
82 SQLRETURN(SQL_API* BindParameter)(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType,
83 SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN* pcbValue);
84 SQLRETURN(SQL_API* NumParams)(SQLHSTMT StatementHandle, SQLSMALLINT* ParameterCountPtr);
85 SQLRETURN(SQL_API* RowCount)(SQLHSTMT StatementHandle, SQLLEN* RowCount);
86 } gate_odbc_functions_t;
87
88 static gate_odbc_functions_t SQL = GATE_INIT_EMPTY;
89
90 #if defined(GATE_SYS_WIN)
91 static const gate_string_t lib_name = GATE_STRING_INIT_STATIC("odbc32");
92 #else
93 static const gate_string_t lib_name = GATE_STRING_INIT_STATIC("libodbc.so");
94 #endif
95
96 #define Name_AllocConnect "SQLAllocConnect"
97 #define Name_FreeEnv "SQLFreeEnv"
98 #define Name_FreeConnect "SQLFreeConnect"
99 #define Name_Disconnect "SQLDisconnect"
100 #define Name_AllocStmt "SQLAllocStmt"
101 #define Name_Fetch "SQLFetch"
102 #define Name_FreeStmt "SQLFreeStmt"
103 #define Name_GetData "SQLGetData"
104 #define Name_AllocEnv "SQLAllocEnv"
105 #define Name_Execute "SQLExecute"
106 #define Name_NumResultCols "SQLNumResultCols"
107 #define Name_BindParameter "SQLBindParameter"
108 #define Name_NumParams "SQLNumParams"
109 #define Name_RowCount "SQLRowCount"
110
111 #if defined(GATE_WIN32_UNICODE)
112 # define Name_Connect "SQLConnectW"
113 # define Name_DescribeCol "SQLDescribeColW"
114 # define Name_Prepare "SQLPrepareW"
115 # define Name_GetDiagRec "SQLGetDiagRecW"
116 #else
117 # define Name_Connect "SQLConnect"
118 # define Name_DescribeCol "SQLDescribeCol"
119 # define Name_Prepare "SQLPrepare"
120 # define Name_GetDiagRec "SQLGetDiagRec"
121 #endif
122
123 4 static gate_result_t load_odbc_functions()
124 {
125 static gate_library_t odbc_lib = NULL;
126 gate_result_t ret;
127 4 gate_library_t lib = NULL;
128
129 do
130 {
131
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (odbc_lib != NULL)
132 {
133 3 ret = GATE_RESULT_OK;
134 3 break;
135 }
136
137 1 ret = gate_library_open(&lib_name, &lib, 0);
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
139
140 1 ret = gate_library_get_function_name(lib, Name_AllocConnect, &SQL.AllocConnect);
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
142 1 ret = gate_library_get_function_name(lib, Name_FreeEnv, &SQL.FreeEnv);
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
144 1 ret = gate_library_get_function_name(lib, Name_FreeConnect, &SQL.FreeConnect);
145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
146 1 ret = gate_library_get_function_name(lib, Name_Disconnect, &SQL.Disconnect);
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
148 1 ret = gate_library_get_function_name(lib, Name_AllocStmt, &SQL.AllocStmt);
149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
150 1 ret = gate_library_get_function_name(lib, Name_Fetch, &SQL.Fetch);
151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
152 1 ret = gate_library_get_function_name(lib, Name_FreeStmt, &SQL.FreeStmt);
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
154 1 ret = gate_library_get_function_name(lib, Name_GetData, &SQL.GetData);
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
156 1 ret = gate_library_get_function_name(lib, Name_AllocEnv, &SQL.AllocEnv);
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
158 1 ret = gate_library_get_function_name(lib, Name_Execute, &SQL.Execute);
159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
160 1 ret = gate_library_get_function_name(lib, Name_NumResultCols, &SQL.NumResultCols);
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
162 1 ret = gate_library_get_function_name(lib, Name_Connect, &SQL.Connect);
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
164 1 ret = gate_library_get_function_name(lib, Name_DescribeCol, &SQL.DescribeCol);
165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
166 1 ret = gate_library_get_function_name(lib, Name_Prepare, &SQL.Prepare);
167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
168 1 ret = gate_library_get_function_name(lib, Name_GetDiagRec, &SQL.GetDiagRec);
169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
170 1 ret = gate_library_get_function_name(lib, Name_BindParameter, &SQL.BindParameter);
171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
172 1 ret = gate_library_get_function_name(lib, Name_NumParams, &SQL.NumParams);
173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
174 1 ret = gate_library_get_function_name(lib, Name_RowCount, &SQL.RowCount);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
176
177 1 odbc_lib = lib;
178 1 lib = NULL;
179 1 ret = GATE_RESULT_OK;
180 } while (0);
181
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (lib != NULL)
183 {
184 gate_library_close(lib);
185 }
186
187 4 return ret;
188 }
189
190
191
192 41 static gate_bool_t gate_data_reader_odbc_is_valid(gate_data_reader_base_t* reader)
193 {
194 41 SQLHSTMT stmt = (SQLHSTMT)reader->native_handles[0];
195 41 return stmt != NULL;
196 }
197
198 6 static gate_result_t gate_data_reader_odbc_close(gate_data_reader_base_t* reader)
199 {
200 6 reader->native_handles[0] = NULL;
201 6 return GATE_RESULT_OK;
202 }
203
204 13 static SQLSMALLINT gate_data_reader_odbc_patch_sql_type(SQLSMALLINT defined_type)
205 {
206 /* some types are defined but in SQLGetData another type must be used */
207
2/3
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
13 switch (defined_type)
208 {
209 6 case SQL_DECIMAL:
210 case SQL_NUMERIC:
211 case SQL_CHAR:
212 case SQL_VARCHAR:
213 6 case SQL_LONGVARCHAR: return SQL_CHAR;
214 case SQL_WVARCHAR:
215 case SQL_WLONGVARCHAR: return SQL_WCHAR;
216 7 default: break;
217 }
218 7 return defined_type;
219 }
220
221 13 static gate_value_t* gate_data_reader_odbc_get_value(SQLHSTMT hstmt, SQLUSMALLINT index, SQLSMALLINT sql_type, gate_value_t* value)
222 {
223 13 gate_value_t* ret = NULL;
224 13 char buffer[8192] = GATE_INIT_EMPTY;
225 13 SQLLEN buffer_used = 0;
226 SQLRETURN sql_res;
227 gate_bool_t bool_val;
228 13 gate_strbuilder_t text_builder = GATE_INIT_EMPTY;
229 13 gate_string_t text = GATE_STRING_INIT_EMPTY;
230 13 gate_arraylist_t arrlst = NULL;
231 13 gate_array_t arr = GATE_INIT_EMPTY;
232 13 SQLGUID const* ptr_sql_guid = NULL;
233 gate_guid_t guid;
234 13 DATE_STRUCT const* ptr_date_struct = NULL;
235 13 TIME_STRUCT const* ptr_time_struct = NULL;
236 13 TIMESTAMP_STRUCT const* ptr_timestamp_struct = NULL;
237 gate_datetime_t dt;
238
239 13 sql_type = gate_data_reader_odbc_patch_sql_type(sql_type);
240
241 13 sql_res = SQL.GetData(hstmt, index, sql_type, buffer, sizeof(buffer), &buffer_used);
242
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 switch (sql_res)
243 {
244 13 case SQL_SUCCESS:
245 case SQL_NO_DATA:
246 case SQL_SUCCESS_WITH_INFO:
247 {
248 /* OK, continue */
249 13 break;
250 }
251 default:
252 {
253 /* error case */
254 return ret;
255 }
256 }
257
258
4/20
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
13 switch (sql_type)
259 {
260 case SQL_C_STINYINT:
261 case SQL_TINYINT: { ret = gate_value_create(GATE_TYPE_I8, buffer, value); break; }
262 case SQL_C_SSHORT:
263 case SQL_SMALLINT: { ret = gate_value_create(GATE_TYPE_I16, buffer, value); break; }
264 5 case SQL_C_SLONG:
265 5 case SQL_INTEGER: { ret = gate_value_create(GATE_TYPE_I32, buffer, value); break; }
266 case SQL_C_SBIGINT:
267 case SQL_BIGINT: { ret = gate_value_create(GATE_TYPE_I64, buffer, value); break; }
268 case SQL_REAL: { ret = gate_value_create(GATE_TYPE_R32, buffer, value); break; }
269 case SQL_FLOAT: { ret = gate_value_create(GATE_TYPE_R32, buffer, value); break; }
270 1 case SQL_DOUBLE: { ret = gate_value_create(GATE_TYPE_R64, buffer, value); break; }
271 case SQL_C_UTINYINT: { ret = gate_value_create(GATE_TYPE_UI8, buffer, value); break; }
272 case SQL_C_USHORT: { ret = gate_value_create(GATE_TYPE_UI16, buffer, value); break; }
273 case SQL_C_ULONG: { ret = gate_value_create(GATE_TYPE_UI32, buffer, value); break; }
274 case SQL_C_UBIGINT: { ret = gate_value_create(GATE_TYPE_UI64, buffer, value); break; }
275 case SQL_BIT:
276 {
277 bool_val = buffer[0] == 0 ? false : true;
278 ret = gate_value_create(GATE_TYPE_BOOL, &bool_val, value);
279 break;
280 }
281
282 6 case SQL_DECIMAL:
283 case SQL_NUMERIC:
284 case SQL_CHAR:
285 case SQL_VARCHAR:
286 case SQL_LONGVARCHAR:
287 {
288 /* extract byte data */
289 6 gate_strbuilder_create(&text_builder, 0);
290 6 gate_strbuilder_append_text(&text_builder, &buffer[0], buffer_used);
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 while (sql_res == SQL_SUCCESS_WITH_INFO)
292 {
293 sql_res = SQL.GetData(hstmt, index, sql_type, buffer, sizeof(buffer), &buffer_used);
294 gate_strbuilder_append_text(&text_builder, &buffer[0], buffer_used);
295 }
296 6 gate_strbuilder_to_string(&text_builder, &text);
297 6 ret = gate_value_create(GATE_TYPE_STRING, &text, value);
298 6 gate_string_release(&text);
299 6 gate_strbuilder_release(&text_builder);
300 6 break;
301 }
302 case SQL_WCHAR:
303 case SQL_WVARCHAR:
304 case SQL_WLONGVARCHAR:
305 {
306 /* extract UTF16 text */
307 gate_strbuilder_create(&text_builder, 0);
308 gate_strbuilder_append_text16(&text_builder, (gate_char16_t const*)&buffer[0], buffer_used / sizeof(gate_char16_t));
309 while (sql_res == SQL_SUCCESS_WITH_INFO)
310 {
311 sql_res = SQL.GetData(hstmt, index, sql_type, buffer, sizeof(buffer), &buffer_used);
312 gate_strbuilder_append_text16(&text_builder, (gate_char16_t const*)&buffer[0], buffer_used / sizeof(gate_char16_t));
313 }
314 gate_strbuilder_to_string(&text_builder, &text);
315 ret = gate_value_create(GATE_TYPE_STRING, &text, value);
316 gate_string_release(&text);
317 gate_strbuilder_release(&text_builder);
318 break;
319 }
320 1 case SQL_BINARY:
321 case SQL_VARBINARY:
322 case SQL_LONGVARBINARY:
323 {
324 1 arrlst = gate_arraylist_create(1, buffer, buffer_used, NULL, NULL);
325
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (arrlst)
326 {
327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 while (sql_res == SQL_SUCCESS_WITH_INFO)
328 {
329 sql_res = SQL.GetData(hstmt, index, sql_type, buffer, sizeof(buffer), &buffer_used);
330 gate_arraylist_add_n(arrlst, buffer, buffer_used);
331 }
332
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (NULL != gate_array_create(&arr, arrlst))
333 {
334 1 ret = gate_value_create(GATE_TYPE_ARRAY, &arr, value);
335 1 gate_array_release(&arr);
336 }
337 1 gate_arraylist_release(arrlst);
338 }
339 1 break;
340 }
341 case SQL_GUID:
342 {
343 ptr_sql_guid = (SQLGUID const*)&buffer[0];
344 guid.item1 = ptr_sql_guid->Data1;
345 guid.item2 = ptr_sql_guid->Data2;
346 guid.item3 = ptr_sql_guid->Data3;
347 gate_mem_copy(guid.item4, ptr_sql_guid->Data4, 8);
348 ret = gate_value_create(GATE_TYPE_GUID, &guid, value);
349 break;
350 }
351 case SQL_TYPE_DATE:
352 {
353 ptr_date_struct = (DATE_STRUCT const*)&buffer[0];
354 dt.date.year = ptr_date_struct->year;
355 dt.date.month = (gate_uint8_t)ptr_date_struct->month;
356 dt.date.day = (gate_uint8_t)ptr_date_struct->day;
357 ret = gate_value_create(GATE_TYPE_DATE, &dt.date, value);
358 break;
359 }
360 case SQL_TYPE_TIME:
361 {
362 ptr_time_struct = (TIME_STRUCT const*)&buffer[0];
363 dt.time.hour = (gate_uint8_t)ptr_time_struct->hour;
364 dt.time.minute = (gate_uint8_t)ptr_time_struct->minute;
365 dt.time.second = (gate_uint8_t)ptr_time_struct->second;
366 dt.time.microsecond = 0;
367 ret = gate_value_create(GATE_TYPE_DAYTIME, &dt.time, value);
368 break;
369 }
370 case SQL_TYPE_TIMESTAMP:
371 {
372 ptr_timestamp_struct = (TIMESTAMP_STRUCT const*)&buffer[0];
373 dt.date.year = ptr_timestamp_struct->year;
374 dt.date.month = (gate_uint8_t)ptr_timestamp_struct->month;
375 dt.date.day = (gate_uint8_t)ptr_timestamp_struct->day;
376 dt.time.hour = (gate_uint8_t)ptr_timestamp_struct->hour;
377 dt.time.minute = (gate_uint8_t)ptr_timestamp_struct->minute;
378 dt.time.second = (gate_uint8_t)ptr_timestamp_struct->second;
379 dt.time.microsecond = ptr_timestamp_struct->fraction / 1000; /*fraction == nanoseconds */
380 ret = gate_value_create(GATE_TYPE_DAYTIME, &dt.time, value);
381 break;
382 }
383 default:
384 {
385 /* not supported */
386 break;
387 }
388 }
389
390 13 return ret;
391 }
392
393 4 static gate_result_t gate_data_reader_odbc_next(gate_data_reader_base_t* reader)
394 {
395 4 gate_result_t ret = GATE_RESULT_FAILED;
396 4 SQLHSTMT hstmt = (SQLHSTMT)reader->native_handles[0];
397 SQLRETURN sql_res;
398 gate_size_t ndx;
399
400 do
401 {
402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (hstmt == NULL)
403 {
404 ret = GATE_RESULT_INVALIDSTATE;
405 break;
406 }
407
408 4 sql_res = SQL.Fetch(hstmt);
409
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (SQL_NO_DATA == sql_res)
410 {
411 2 gate_data_reader_base_close(reader);
412 2 ret = GATE_RESULT_ENDOFSTREAM;
413 2 break;
414 }
415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (SQL_SUCCESS != sql_res)
416 {
417 ret = GATE_RESULT_FAILED;
418 break;
419 }
420
421 2 ret = GATE_RESULT_OK;
422
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 for (ndx = 0; ndx != reader->field_count; ++ndx)
423 {
424 13 gate_value_release(&reader->values[ndx]);
425 13 gate_data_reader_odbc_get_value(hstmt, (SQLUSMALLINT)(ndx + 1), (SQLUSMALLINT)reader->types[ndx], &reader->values[ndx]);
426 }
427
428 } while (0);
429
430 4 return ret;
431 }
432
433
434 2 static gate_result_t gate_data_reader_odbc_init(gate_data_reader_base_t* reader)
435 {
436 2 gate_result_t ret = GATE_RESULT_OK;
437 2 SQLSMALLINT col_count = 0;
438 SQLSMALLINT col_index;
439 SQLRETURN sql_ret;
440 2 SQLHSTMT hstmt = (SQLHSTMT)reader->native_handles[0];
441 SQLTCHAR colname[1024];
442 SQLSMALLINT colname_len;
443 SQLSMALLINT coltype;
444 SQLULEN colvalue_len;
445 SQLSMALLINT colvalue_digits;
446 SQLSMALLINT colvalue_nullable;
447
448 do
449 {
450 2 sql_ret = SQL.NumResultCols(hstmt, &col_count);
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (SQL_SUCCESS != sql_ret)
452 {
453 ret = GATE_RESULT_FAILED;
454 break;
455 }
456 2 reader->field_count = col_count;
457
458
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 for (col_index = 0; col_index != col_count; ++col_index)
459 {
460 13 colname_len = sizeof(colname) / sizeof(colname[0]);
461 13 coltype = 0;
462 13 colvalue_len = 0;
463 13 colvalue_digits = 0;
464 13 colvalue_nullable = 0;
465 13 sql_ret = SQL.DescribeCol(hstmt, (SQLUSMALLINT)(col_index + 1), colname, colname_len, &colname_len,
466 &coltype, &colvalue_len, &colvalue_digits, &colvalue_nullable);
467 #if defined(GATE_SYS_WIN)
468 gate_win32_winstr_2_utf8_string((LPCTSTR)&colname[0], colname_len, &reader->names[col_index]);
469 #else
470 13 gate_string_create(&reader->names[col_index], (char const*)&colname[0], colname_len);
471 #endif
472 13 reader->types[col_index] = coltype;
473 }
474 } while (0);
475
476 2 return ret;
477 }
478
479
480 2 static gate_data_reader_t* gate_data_reader_odbc_create(gate_data_statement_base_t* ptr_statement, SQLHSTMT stmt)
481 {
482 2 gate_data_reader_t* ret = NULL;
483 2 gate_data_handles_t handles = GATE_INIT_EMPTY;
484
485 2 handles[0] = (void*)stmt;
486
487 2 ret = gate_data_reader_base_create(
488 (gate_data_statement_t*)ptr_statement, handles,
489 &gate_data_reader_odbc_init,
490 &gate_data_reader_odbc_is_valid,
491 &gate_data_reader_odbc_next,
492 &gate_data_reader_odbc_close);
493
494 2 return ret;
495 }
496
497 typedef union odbc_param_value {
498 SQLINTEGER sql_int;
499 SQLBIGINT sql_bigint;
500 SQLDOUBLE sql_double;
501 SQL_TIMESTAMP_STRUCT sql_timestamp;
502 gate_string_t text;
503 gate_blob_t blob;
504 } odbc_param_value_t;
505
506 typedef struct odbc_param {
507 SQLSMALLINT index; /* parameter index*/
508 odbc_param_value_t value; /* assigned value to parameter */
509 gate_mem_dtor_t dtor; /* destructor of value */
510 SQLLEN length; /* bind-length of value */
511 } odbc_param_t;
512
513 12 static void GATE_CALL odbc_param_dtor(void* dest)
514 {
515 12 odbc_param_t* const ptr = (odbc_param_t*)dest;
516
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (ptr->dtor)
517 {
518 4 ptr->dtor(&ptr->value);
519 4 ptr->dtor = NULL;
520 }
521 12 gate_mem_clear(ptr, sizeof(odbc_param_t));
522 12 }
523
524 12 static odbc_param_t* odbc_param_get(gate_slotlist_t* param_cache, SQLSMALLINT paramIndex)
525 {
526 gate_slotlist_iterator_t iter;
527 void* cache_item;
528 odbc_param_t* ptr_param;
529 12 cache_item = gate_slotlist_first(param_cache, &iter);
530 /* search already existing paramIndex */
531
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 12 times.
37 while (cache_item != NULL)
532 {
533 25 ptr_param = (odbc_param_t*)cache_item;
534
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (ptr_param->index == paramIndex)
535 {
536 /* clean-up previous value fields */
537 odbc_param_dtor(ptr_param);
538 /* re-init empty value with index*/
539 ptr_param->index = paramIndex;
540 return ptr_param;
541 }
542 25 cache_item = gate_slotlist_next(param_cache, &iter);
543 }
544 /* paramIndex does not exist -> create new entry */
545 12 ptr_param = (odbc_param_t*)gate_mem_alloc(sizeof(odbc_param_t));
546
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (NULL != ptr_param)
547 {
548 12 gate_mem_clear(ptr_param, sizeof(odbc_param_t));
549 12 ptr_param->index = paramIndex;
550 12 gate_slotlist_import(param_cache, ptr_param);
551 }
552 12 return ptr_param;
553 }
554
555 11 static gate_result_t odbcstmt_init(gate_data_statement_base_t* self)
556 {
557 11 gate_slotlist_t* ptr_slots = (gate_slotlist_t*)gate_mem_alloc(sizeof(gate_slotlist_t));
558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ptr_slots == NULL)
559 {
560 return GATE_RESULT_OUTOFMEMORY;
561 }
562
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 if (NULL == gate_slotlist_create(ptr_slots, sizeof(odbc_param_t), NULL, &odbc_param_dtor))
563 {
564 gate_mem_dealloc(ptr_slots);
565 return GATE_RESULT_OUTOFMEMORY;
566 }
567 11 self->native_handles[2] = (void*)ptr_slots;
568 11 return GATE_RESULT_OK;
569 }
570
571 11 static void odbcstmt_close(gate_data_statement_base_t* self)
572 {
573 11 SQLHSTMT const hstmt = (SQLHSTMT)self->native_handles[1];
574 11 gate_slotlist_t* const ptr_slots = (gate_slotlist_t*)self->native_handles[2];
575
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (hstmt != NULL)
576 {
577 11 SQL.FreeStmt(hstmt, SQL_CLOSE);
578 11 SQL.FreeStmt(hstmt, SQL_DROP);
579 11 self->native_handles[1] = NULL;
580 }
581
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (ptr_slots != NULL)
582 {
583 11 gate_slotlist_destroy(ptr_slots);
584 11 gate_mem_dealloc(ptr_slots);
585 11 self->native_handles[2] = NULL;
586 }
587 11 }
588
589 12 static gate_result_t odbcstmt_convert_result(SQLRETURN sql_result, SQLHANDLE sql_handle)
590 {
591
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (SQL_SUCCEEDED(sql_result))
592 {
593 12 return GATE_RESULT_OK;
594 }
595 else
596 {
597 if (sql_handle != NULL)
598 {
599 SQLTCHAR sqlState[32] = GATE_INIT_EMPTY;
600 SQLINTEGER native_error_code = 0;
601 SQLTCHAR sqlMsg[1024] = GATE_INIT_EMPTY;
602 SQLSMALLINT sqlMsgLen = 0;
603 SQL.GetDiagRec(SQL_HANDLE_STMT, sql_handle, 1, sqlState, &native_error_code, sqlMsg, sizeof(sqlMsg) / sizeof(sqlMsg[0]), &sqlMsgLen);
604 return GATE_RESULT_FAILED;
605 }
606 /* TODO: detailed error analysis */
607 return GATE_RESULT_FAILED;
608 }
609 }
610
611 static gate_result_t odbcstmt_set_null_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_slotlist_t* param_cache)
612 {
613 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
614 if (NULL == ptr_param)
615 {
616 return GATE_RESULT_OUTOFMEMORY;
617 }
618 else
619 {
620 SQLRETURN sql_result;
621 ptr_param->length = SQL_NULL_DATA;
622 sql_result = SQL.BindParameter(
623 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, NULL, 0, &ptr_param->length);
624 return odbcstmt_convert_result(sql_result, hstmt);
625 }
626 }
627
628 static gate_result_t odbcstmt_set_bigint_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_int64_t value, gate_slotlist_t* param_cache)
629 {
630 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
631 if (NULL == ptr_param)
632 {
633 return GATE_RESULT_OUTOFMEMORY;
634 }
635 else
636 {
637 SQLRETURN sql_result;
638 ptr_param->length = 0;
639 ptr_param->value.sql_bigint = value;
640 sql_result = SQL.BindParameter(
641 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, &ptr_param->value.sql_bigint, 0, &ptr_param->length);
642 return odbcstmt_convert_result(sql_result, hstmt);
643 }
644 }
645
646 4 static gate_result_t odbcstmt_set_int_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_int32_t value, gate_slotlist_t* param_cache)
647 {
648 4 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == ptr_param)
650 {
651 return GATE_RESULT_OUTOFMEMORY;
652 }
653 else
654 {
655 SQLRETURN sql_result;
656 4 ptr_param->length = 0;
657 4 ptr_param->value.sql_int = value;
658 8 sql_result = SQL.BindParameter(
659 4 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &ptr_param->value.sql_int, 0, &ptr_param->length);
660 4 return odbcstmt_convert_result(sql_result, hstmt);
661 }
662 }
663
664 1 static gate_result_t odbcstmt_set_real_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_real64_t value, gate_slotlist_t* param_cache)
665 {
666 1 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
667
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == ptr_param)
668 {
669 return GATE_RESULT_OUTOFMEMORY;
670 }
671 else
672 {
673 SQLRETURN sql_result;
674 1 ptr_param->length = 0;
675 1 ptr_param->value.sql_double = value;
676 2 sql_result = SQL.BindParameter(
677 1 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &ptr_param->value.sql_double, 0, &ptr_param->length);
678 1 return odbcstmt_convert_result(sql_result, hstmt);
679 }
680 }
681
682 3 static gate_result_t odbcstmt_set_text_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, char const* text, gate_size_t textlen, gate_slotlist_t* param_cache)
683 {
684 3 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == ptr_param)
686 {
687 return GATE_RESULT_OUTOFMEMORY;
688 }
689 else
690 {
691 SQLRETURN sql_result;
692
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL == gate_string_create(&ptr_param->value.text, text, textlen))
693 {
694 return GATE_RESULT_OUTOFMEMORY;
695 }
696 3 ptr_param->dtor = &gate_string_destructor;
697 3 ptr_param->length = textlen;
698 6 sql_result = SQL.BindParameter(
699 3 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, (SQLULEN)textlen, 0, (char*)ptr_param->value.text.str, 0, &ptr_param->length);
700 3 return odbcstmt_convert_result(sql_result, hstmt);
701 }
702 }
703
704 1 static gate_result_t odbcstmt_set_binary_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, void const* data, gate_size_t datalen, gate_slotlist_t* param_cache)
705 {
706 1 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == ptr_param)
708 {
709 return GATE_RESULT_OUTOFMEMORY;
710 }
711 else
712 {
713 SQLRETURN sql_result;
714
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_blob_create(&ptr_param->value.blob, data, datalen))
715 {
716 return GATE_RESULT_OUTOFMEMORY;
717 }
718 1 ptr_param->dtor = &gate_blob_destructor;
719 1 ptr_param->length = datalen;
720 2 sql_result = SQL.BindParameter(
721 1 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER)ptr_param->value.blob.data, 0, &ptr_param->length);
722 1 return odbcstmt_convert_result(sql_result, hstmt);
723 }
724 }
725
726 3 static gate_result_t odbcstmt_set_datetime_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_datetime_t const* dt, gate_slotlist_t* param_cache)
727 {
728 3 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
729
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == ptr_param)
730 {
731 return GATE_RESULT_OUTOFMEMORY;
732 }
733 else
734 {
735 SQLRETURN sql_result;
736 3 SQL_TIMESTAMP_STRUCT* sql_dt = &ptr_param->value.sql_timestamp;
737 3 sql_dt->year = dt->date.year;
738 3 sql_dt->month = dt->date.month;
739 3 sql_dt->day = dt->date.day;
740 3 sql_dt->hour = dt->time.hour;
741 3 sql_dt->minute = dt->time.minute;
742 3 sql_dt->second = dt->time.second;
743 3 sql_dt->fraction = 0;
744 3 ptr_param->length = sizeof(SQL_TIMESTAMP_STRUCT);
745
746
747 3 sql_result = SQL.BindParameter(
748 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 0, 0, sql_dt, ptr_param->length, &ptr_param->length);
749
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!SQL_SUCCEEDED(sql_result))
750 {
751 /* ODBC Date-time structs are not supported by all drivers, try text-representation: */
752 gate_result_t result;
753 char str[32] = GATE_INIT_EMPTY;
754 gate_size_t len = sizeof(str);
755 result = gate_date_to_string(dt, 0, "{YYYY}-{MM}-{DD} {hh}:{mm}:{ss}", str, &len);
756 if (GATE_SUCCEEDED(result))
757 {
758 return odbcstmt_set_text_param(hstmt, odbc_index, str, len, param_cache);
759 }
760 }
761 3 return odbcstmt_convert_result(sql_result, hstmt);
762 }
763 }
764
765
766 12 static gate_result_t odbcstmt_set_param(gate_data_statement_base_t* self, gate_size_t index, gate_value_t const* value)
767 {
768 12 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
769 12 SQLUSMALLINT odbc_index = (SQLUSMALLINT)(index);
770 12 gate_slotlist_t* ptr_slots = (gate_slotlist_t*)self->native_handles[2];
771 gate_cstrbuffer8_t buffer;
772 12 gate_datetime_t dt = GATE_INIT_EMPTY;
773 12 gate_result_t ret = GATE_RESULT_FAILED;
774
775
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 if ((value == NULL) || (value->value_type == GATE_TYPE_EMPTY))
776 {
777 return odbcstmt_set_null_param(hstmt, odbc_index, ptr_slots);
778 }
779
780
11/20
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 1 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 1 times.
✓ Branch 17 taken 1 times.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
12 switch (value->value_type)
781 {
782 case GATE_TYPE_BOOL: return odbcstmt_set_int_param(hstmt, odbc_index, value->content.bool_value ? 1 : 0, ptr_slots);
783 1 case GATE_TYPE_I8: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.i8_value, ptr_slots);
784 1 case GATE_TYPE_I16: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.i16_value, ptr_slots);
785 2 case GATE_TYPE_I32: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.i32_value, ptr_slots);
786 case GATE_TYPE_I64: return odbcstmt_set_bigint_param(hstmt, odbc_index, (gate_int32_t)value->content.i64_value, ptr_slots);
787 case GATE_TYPE_UI8: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.ui8_value, ptr_slots);
788 case GATE_TYPE_UI16: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.ui16_value, ptr_slots);
789 case GATE_TYPE_UI32: return odbcstmt_set_bigint_param(hstmt, odbc_index, (gate_int64_t)value->content.ui32_value, ptr_slots);
790 case GATE_TYPE_UI64: return odbcstmt_set_bigint_param(hstmt, odbc_index, (gate_int64_t)value->content.ui64_value, ptr_slots);
791
792 1 case GATE_TYPE_R32: return odbcstmt_set_real_param(hstmt, odbc_index, (gate_real64_t)value->content.r32_value, ptr_slots);
793 case GATE_TYPE_R64: return odbcstmt_set_real_param(hstmt, odbc_index, (gate_real64_t)value->content.r64_value, ptr_slots);
794
795 1 case GATE_TYPE_BLOB: return odbcstmt_set_binary_param(hstmt, odbc_index, value->content.blob_value.data, value->content.blob_value.length, ptr_slots);
796
797 case GATE_TYPE_CSTR: return odbcstmt_set_text_param(hstmt, odbc_index, value->content.cstring_value, gate_str_length(value->content.cstring_value), ptr_slots);
798 1 case GATE_TYPE_STRING: return odbcstmt_set_text_param(hstmt, odbc_index, value->content.string_value.str, value->content.string_value.length, ptr_slots);
799
800 1 case GATE_TYPE_WSTR:
801 {
802
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (NULL == gate_cstrbuffer_create_wstr(&buffer, value->content.wstring_value, gate_wstr_length(value->content.wstring_value)))
803 {
804 return GATE_RESULT_OUTOFMEMORY;
805 }
806 1 ret = odbcstmt_set_text_param(hstmt, odbc_index, gate_cstrbuffer_get(&buffer), gate_cstrbuffer_length(&buffer), ptr_slots);
807 1 gate_cstrbuffer_destroy(&buffer);
808 1 return ret;
809 }
810 1 case GATE_TYPE_GUID:
811 {
812 1 ret = gate_guid_to_string(&value->content.guid_value, buffer.local_buffer);
813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_RETURN_IF_FAILED(ret);
814 1 return odbcstmt_set_text_param(hstmt, odbc_index, buffer.local_buffer, gate_str_length(buffer.local_buffer), ptr_slots);
815 }
816 1 case GATE_TYPE_DATE:
817 {
818 1 dt.date = value->content.date_value;
819 1 return odbcstmt_set_datetime_param(hstmt, odbc_index, &dt, ptr_slots);
820 }
821 1 case GATE_TYPE_DATETIME:
822 {
823 1 return odbcstmt_set_datetime_param(hstmt, odbc_index, &value->content.datetime_value, ptr_slots);
824 }
825 1 case GATE_TYPE_TIME:
826 {
827 1 ret = gate_time_to_datetime(&value->content.time_value, &dt);
828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_RETURN_IF_FAILED(ret);
829 1 return odbcstmt_set_datetime_param(hstmt, odbc_index, &dt, ptr_slots);
830 }
831 case GATE_TYPE_PROPERTY:
832 default:
833 return GATE_RESULT_INCORRECTTYPE;
834 }
835 }
836
837 static gate_result_t odbcstmt_set_named_param(gate_data_statement_base_t* self, gate_string_t const* name, gate_value_t const* value)
838 {
839 /* named parameters are not supported by odbc */
840 return GATE_RESULT_NOTSUPPORTED;
841 }
842
843 3 static gate_result_t odbcstmt_reset(gate_data_statement_base_t* self)
844 {
845 SQLRETURN sql_ret;
846 3 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
847
848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (hstmt == NULL)
849 {
850 return GATE_RESULT_INVALIDSTATE;
851 }
852
853 3 sql_ret = SQL.FreeStmt(hstmt, SQL_RESET_PARAMS);
854
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 switch (sql_ret)
855 {
856 3 case SQL_SUCCESS:
857 case SQL_SUCCESS_WITH_INFO:
858 3 return GATE_RESULT_OK;
859 default:
860 return GATE_RESULT_FAILED;
861 }
862 }
863
864 9 static gate_result_t odbcstmt_execute(gate_data_statement_base_t* self, gate_int32_t* affected_rows)
865 {
866 SQLRETURN sql_ret;
867 9 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
868 9 SQLLEN len_rows = 0;
869
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (hstmt == NULL)
871 {
872 return GATE_RESULT_INVALIDSTATE;
873 }
874
875 9 sql_ret = SQL.Execute(hstmt);
876
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9 if ((SQL_SUCCESS != sql_ret) && (SQL_SUCCESS_WITH_INFO != sql_ret))
877 {
878 SQLTCHAR sqlState[32] = GATE_INIT_EMPTY;
879 SQLINTEGER native_error_code = 0;
880 SQLTCHAR sqlMsg[1024] = GATE_INIT_EMPTY;
881 SQLSMALLINT sqlMsgLen = 0;
882 SQL.GetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sqlState, &native_error_code, sqlMsg, sizeof(sqlMsg) / sizeof(sqlMsg[0]), &sqlMsgLen);
883 return GATE_RESULT_FAILED;
884 }
885
886 /* success case */
887
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (affected_rows)
888 {
889 9 SQL.RowCount(hstmt, &len_rows);
890 9 *affected_rows = (gate_int32_t)len_rows;
891 }
892 9 return GATE_RESULT_OK;
893 }
894
895 2 static gate_result_t odbcstmt_query(gate_data_statement_base_t* self, gate_data_reader_t** ptr_reader)
896 {
897 SQLRETURN sql_ret;
898 2 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
899 2 SQLLEN len_rows = 0;
900
901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (hstmt == NULL)
902 {
903 return GATE_RESULT_INVALIDSTATE;
904 }
905
906 2 sql_ret = SQL.Execute(hstmt);
907
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if ((SQL_SUCCESS != sql_ret) && (SQL_SUCCESS_WITH_INFO != sql_ret))
908 {
909 SQLTCHAR sqlState[32] = GATE_INIT_EMPTY;
910 SQLINTEGER native_error_code = 0;
911 SQLTCHAR sqlMsg[1024] = GATE_INIT_EMPTY;
912 SQLSMALLINT sqlMsgLen = 0;
913 SQL.GetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sqlState, &native_error_code, sqlMsg, sizeof(sqlMsg) / sizeof(sqlMsg[0]), &sqlMsgLen);
914 return GATE_RESULT_FAILED;
915 }
916
917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ptr_reader == NULL)
918 {
919 /* success, reader not required, free unused resources */
920 SQL.FreeStmt(hstmt, SQL_CLOSE);
921 SQL.FreeStmt(hstmt, SQL_DROP);
922 return GATE_RESULT_OK;
923 }
924
925 2 *ptr_reader = gate_data_reader_odbc_create(self, hstmt);
926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (*ptr_reader == NULL)
927 {
928 /* failed to allocate data reader */
929 SQL.FreeStmt(hstmt, SQL_CLOSE);
930 SQL.FreeStmt(hstmt, SQL_DROP);
931 return GATE_RESULT_FAILED;
932 }
933 2 return GATE_RESULT_OK;
934
935 }
936
937
938
939
940
941
942
943
944 11 gate_result_t gate_data_connection_odbc_create_statement(gate_data_connection_base_t* self, gate_string_t const* sql, gate_data_statement_t** ptr_stmt)
945 {
946 11 gate_result_t ret = GATE_RESULT_FAILED;
947 11 SQLHSTMT hstmt = NULL;
948 11 SQLHDBC hdbc = self->native_handles[0];
949 SQLRETURN sql_ret;
950 SQLTCHAR cmd[4096 + 2048 + 1024];
951 11 SQLSMALLINT param_count = 0;
952 gate_size_t cmd_len;
953 gate_data_handles_t handles;
954 11 gate_data_statement_base_t* ptr_stmt_base = NULL;
955
956 do
957 {
958 #if defined(GATE_SYS_WIN)
959 cmd_len = gate_win32_utf8_2_winstr(sql->str, sql->length, (LPTSTR)&cmd[0], sizeof(cmd) / sizeof(cmd[0]));
960 #else
961 11 cmd_len = gate_string_to_buffer(sql, (char*)&cmd[0], sizeof(cmd) / sizeof(cmd[0]));
962 #endif
963
964 11 sql_ret = SQL.AllocStmt(hdbc, &hstmt);
965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (SQL_SUCCESS != sql_ret)
966 {
967 ret = GATE_RESULT_OUTOFRESOURCES;
968 break;
969 }
970
971 11 sql_ret = SQL.Prepare(hstmt, cmd, (SQLINTEGER)cmd_len);
972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (SQL_SUCCESS != sql_ret)
973 {
974 ret = GATE_RESULT_FAILED;
975 break;
976 }
977
978 11 gate_mem_clear(&handles[0], sizeof(handles));
979 11 handles[0] = (void*)hdbc;
980 11 handles[1] = (void*)hstmt;
981
982 11 ret = gate_data_statement_base_create(
983 self, handles, sql,
984 &odbcstmt_init,
985 &odbcstmt_close,
986 &odbcstmt_set_param,
987 &odbcstmt_set_named_param,
988 &odbcstmt_reset,
989 &odbcstmt_execute,
990 &odbcstmt_query,
991 &ptr_stmt_base);
992
993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 GATE_BREAK_IF_FAILED(ret);
994
995
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 if (SQL_ERROR != SQL.NumParams(hstmt, &param_count))
996 {
997 11 ptr_stmt_base->param_count = param_count;
998 }
999
1000 /* success case: */
1001
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (ptr_stmt != NULL)
1002 {
1003 11 *ptr_stmt = (gate_data_statement_t*)ptr_stmt_base;
1004 11 ptr_stmt_base = NULL;
1005 }
1006 11 hstmt = NULL;
1007 11 ret = GATE_RESULT_OK;
1008 } while (0);
1009
1010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ptr_stmt_base != NULL)
1011 {
1012 gate_object_release(ptr_stmt_base);
1013 }
1014
1015
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (hstmt != NULL)
1016 {
1017 SQL.FreeStmt(hstmt, SQL_CLOSE);
1018 SQL.FreeStmt(hstmt, SQL_DROP);
1019 }
1020 11 return ret;
1021 }
1022
1023 2 static gate_result_t gate_data_connection_odbc_init(gate_data_connection_base_t* self)
1024 {
1025 GATE_UNUSED_ARG(self);
1026 2 return GATE_RESULT_OK;
1027 }
1028
1029 2 static void gate_data_connection_odbc_close(gate_data_connection_base_t* self)
1030 {
1031 2 SQLHDBC hdbc = self->native_handles[0];
1032 2 SQLHENV henv = self->native_handles[1];
1033
1034
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (hdbc != NULL)
1035 {
1036 2 SQL.Disconnect(hdbc);
1037 2 SQL.FreeConnect(hdbc);
1038 }
1039
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (henv != NULL)
1040 {
1041 2 SQL.FreeEnv(henv);
1042 }
1043 2 gate_mem_clear(self->native_handles, sizeof(self->native_handles));
1044 2 }
1045
1046
1047
1048 4 gate_result_t gate_data_adapter_odbc_create(gate_string_t const* path, gate_enumint_t flags, gate_data_connection_t** ptr_connection)
1049 {
1050 4 gate_result_t ret = GATE_RESULT_OK;
1051 SQLTCHAR str_connection[4096];
1052 gate_size_t str_connection_len;
1053 4 SQLTCHAR* str_user = NULL;
1054 4 gate_size_t str_user_len = 0;
1055 4 SQLTCHAR* str_pass = NULL;
1056 4 gate_size_t str_pass_len = 0;
1057 4 SQLHENV henv = NULL;
1058 4 SQLHDBC hdbc = NULL;
1059 SQLRETURN sql_ret;
1060 4 gate_data_handles_t handles = GATE_INIT_EMPTY;
1061
1062 do
1063 {
1064 4 ret = load_odbc_functions();
1065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(ret);
1066
1067 #if defined(GATE_SYS_WIN)
1068 str_connection_len = gate_win32_utf8_2_winstr(path->str, path->length, (LPTSTR)&str_connection[0], sizeof(str_connection) / sizeof(str_connection[0]));
1069 #else
1070 4 str_connection_len = gate_string_to_buffer(path, (char*)&str_connection[0], sizeof(str_connection) / sizeof(str_connection[0]));
1071 #endif
1072
1073
1074 4 sql_ret = SQL.AllocEnv(&henv);
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (SQL_SUCCESS != sql_ret)
1076 {
1077 ret = GATE_RESULT_OUTOFRESOURCES;
1078 break;
1079 }
1080
1081 4 sql_ret = SQL.AllocConnect(henv, &hdbc);
1082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (SQL_SUCCESS != sql_ret)
1083 {
1084 ret = GATE_RESULT_OUTOFRESOURCES;
1085 break;
1086 }
1087
1088 12 sql_ret = SQL.Connect(hdbc, str_connection, (SQLSMALLINT)str_connection_len,
1089 4 str_user, (SQLSMALLINT)str_user_len, str_pass, (SQLSMALLINT)str_pass_len);
1090
1091
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if ((SQL_SUCCESS != sql_ret) && (SQL_SUCCESS_WITH_INFO != sql_ret))
1092 {
1093 SQLTCHAR state_msg[1024];
1094 2 SQLINTEGER native_error = 0;
1095 SQLTCHAR error_msg[1024];
1096 2 SQLSMALLINT error_msg_used = 0;
1097 2 SQL.GetDiagRec(SQL_HANDLE_DBC, hdbc, 1, state_msg, &native_error, error_msg, 1024, &error_msg_used);
1098 2 ret = GATE_RESULT_FAILED;
1099 2 break;
1100 }
1101
1102 2 handles[0] = (void*)hdbc;
1103 2 handles[1] = (void*)henv;
1104 2 ret = gate_data_connection_base_create(
1105 handles,
1106 &gate_data_connection_odbc_init,
1107 &gate_data_connection_odbc_close,
1108 &gate_data_connection_odbc_create_statement,
1109 ptr_connection);
1110
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(ret))
1111 {
1112 2 hdbc = NULL;
1113 2 henv = NULL;
1114 }
1115 } while (0);
1116
1117
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (hdbc)
1118 {
1119 2 SQL.Disconnect(hdbc);
1120 2 SQL.FreeConnect(hdbc);
1121 }
1122
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (henv)
1123 {
1124 2 SQL.FreeEnv(henv);
1125 }
1126 4 return ret;
1127 }
1128
1129 #else /* GATE_DATA_ODBC_IMPL */
1130
1131 gate_result_t gate_data_adapter_odbc_create(gate_string_t const* path, gate_enumint_t flags, gate_data_connection_t** ptr_connection)
1132 {
1133 (void)path;
1134 (void)flags;
1135 (void)ptr_connection;
1136 return GATE_RESULT_NOTIMPLEMENTED;
1137 }
1138
1139 #endif
1140