GCC Code Coverage Report


Directory: src/gate/
File: src/gate/data/odbc_adapter.c
Date: 2026-08-06 22:46:24
Exec Total Coverage
Lines: 349 528 66.1%
Functions: 25 29 86.2%
Branches: 102 219 46.6%

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 static void GATE_CALL odbc_param_dtor(void* dest)
514 {
515 odbc_param_t* ptr = (odbc_param_t*)dest;
516 if (ptr->dtor)
517 {
518 ptr->dtor(&ptr->value);
519 }
520 }
521
522 12 odbc_param_t* odbc_param_get(gate_slotlist_t* param_cache, SQLSMALLINT paramIndex)
523 {
524 gate_slotlist_iterator_t iter;
525 void* cache_item;
526 odbc_param_t* ptr_param;
527 12 cache_item = gate_slotlist_first(param_cache, &iter);
528 /* search already existing paramIndex */
529
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 while (cache_item != NULL)
530 {
531 ptr_param = (odbc_param_t*)cache_item;
532 if (ptr_param->index == paramIndex)
533 {
534 /* clean-up previous value fields */
535 if (ptr_param->dtor != NULL)
536 {
537 ptr_param->dtor(&ptr_param->value);
538 ptr_param->dtor = NULL;
539 }
540 gate_mem_clear(&ptr_param->value, sizeof(odbc_param_value_t));
541 ptr_param->length = 0;
542 return ptr_param;
543 }
544 cache_item = gate_slotlist_next(param_cache, &iter);
545 }
546 /* paramIndex does not exist -> create new entry */
547 12 ptr_param = (odbc_param_t*)gate_mem_alloc(sizeof(odbc_param_t));
548
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (NULL != ptr_param)
549 {
550 12 gate_mem_clear(ptr_param, sizeof(odbc_param_t));
551 12 ptr_param->index = paramIndex;
552 }
553 12 return ptr_param;
554 }
555
556 11 static gate_result_t odbcstmt_init(gate_data_statement_base_t* self)
557 {
558 11 gate_slotlist_t* ptr_slots = (gate_slotlist_t*)gate_mem_alloc(sizeof(gate_slotlist_t));
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ptr_slots == NULL)
560 {
561 return GATE_RESULT_OUTOFMEMORY;
562 }
563
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))
564 {
565 gate_mem_dealloc(ptr_slots);
566 return GATE_RESULT_OUTOFMEMORY;
567 }
568 11 self->native_handles[2] = (void*)ptr_slots;
569 11 return GATE_RESULT_OK;
570 }
571
572 11 static void odbcstmt_close(gate_data_statement_base_t* self)
573 {
574 11 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
575 11 gate_slotlist_t* ptr_slots = (gate_slotlist_t*)self->native_handles[2];
576
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (hstmt != NULL)
577 {
578 11 SQL.FreeStmt(hstmt, SQL_CLOSE);
579 11 SQL.FreeStmt(hstmt, SQL_DROP);
580 11 self->native_handles[1] = NULL;
581 }
582
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (ptr_slots != NULL)
583 {
584 11 gate_slotlist_destroy(ptr_slots);
585 11 gate_mem_dealloc(ptr_slots);
586 11 self->native_handles[2] = NULL;
587 }
588 11 }
589
590 12 static gate_result_t odbcstmt_convert_result(SQLRETURN sql_result, SQLHANDLE sql_handle)
591 {
592
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (SQL_SUCCEEDED(sql_result))
593 {
594 12 return GATE_RESULT_OK;
595 }
596 else
597 {
598 if (sql_handle != NULL)
599 {
600 SQLTCHAR sqlState[32] = GATE_INIT_EMPTY;
601 SQLINTEGER native_error_code = 0;
602 SQLTCHAR sqlMsg[1024] = GATE_INIT_EMPTY;
603 SQLSMALLINT sqlMsgLen = 0;
604 SQL.GetDiagRec(SQL_HANDLE_STMT, sql_handle, 1, sqlState, &native_error_code, sqlMsg, sizeof(sqlMsg) / sizeof(sqlMsg[0]), &sqlMsgLen);
605 return GATE_RESULT_FAILED;
606 }
607 /* TODO: detailed error analysis */
608 return GATE_RESULT_FAILED;
609 }
610 }
611
612 static gate_result_t odbcstmt_set_null_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_slotlist_t* param_cache)
613 {
614 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
615 if (NULL == ptr_param)
616 {
617 return GATE_RESULT_OUTOFMEMORY;
618 }
619 else
620 {
621 SQLRETURN sql_result;
622 ptr_param->length = SQL_NULL_DATA;
623 sql_result = SQL.BindParameter(
624 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, NULL, 0, &ptr_param->length);
625 return odbcstmt_convert_result(sql_result, hstmt);
626 }
627 }
628
629 static gate_result_t odbcstmt_set_bigint_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_int64_t value, gate_slotlist_t* param_cache)
630 {
631 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
632 if (NULL == ptr_param)
633 {
634 return GATE_RESULT_OUTOFMEMORY;
635 }
636 else
637 {
638 SQLRETURN sql_result;
639 ptr_param->length = 0;
640 ptr_param->value.sql_bigint = value;
641 sql_result = SQL.BindParameter(
642 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, &ptr_param->value.sql_bigint, 0, &ptr_param->length);
643 return odbcstmt_convert_result(sql_result, hstmt);
644 }
645 }
646
647 4 static gate_result_t odbcstmt_set_int_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_int32_t value, gate_slotlist_t* param_cache)
648 {
649 4 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
650
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == ptr_param)
651 {
652 return GATE_RESULT_OUTOFMEMORY;
653 }
654 else
655 {
656 SQLRETURN sql_result;
657 4 ptr_param->length = 0;
658 4 ptr_param->value.sql_int = value;
659 8 sql_result = SQL.BindParameter(
660 4 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &ptr_param->value.sql_int, 0, &ptr_param->length);
661 4 return odbcstmt_convert_result(sql_result, hstmt);
662 }
663 }
664
665 1 static gate_result_t odbcstmt_set_real_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_real64_t value, gate_slotlist_t* param_cache)
666 {
667 1 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == ptr_param)
669 {
670 return GATE_RESULT_OUTOFMEMORY;
671 }
672 else
673 {
674 SQLRETURN sql_result;
675 1 ptr_param->length = 0;
676 1 ptr_param->value.sql_double = value;
677 2 sql_result = SQL.BindParameter(
678 1 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &ptr_param->value.sql_double, 0, &ptr_param->length);
679 1 return odbcstmt_convert_result(sql_result, hstmt);
680 }
681 }
682
683 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)
684 {
685 3 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
686
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == ptr_param)
687 {
688 return GATE_RESULT_OUTOFMEMORY;
689 }
690 else
691 {
692 SQLRETURN sql_result;
693
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (NULL == gate_string_create(&ptr_param->value.text, text, textlen))
694 {
695 return GATE_RESULT_OUTOFMEMORY;
696 }
697 3 ptr_param->dtor = &gate_string_destructor;
698 3 ptr_param->length = textlen;
699 6 sql_result = SQL.BindParameter(
700 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);
701 3 return odbcstmt_convert_result(sql_result, hstmt);
702 }
703 }
704
705 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)
706 {
707 1 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == ptr_param)
709 {
710 return GATE_RESULT_OUTOFMEMORY;
711 }
712 else
713 {
714 SQLRETURN sql_result;
715
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_blob_create(&ptr_param->value.blob, data, datalen))
716 {
717 return GATE_RESULT_OUTOFMEMORY;
718 }
719 1 ptr_param->dtor = &gate_blob_destructor;
720 1 ptr_param->length = datalen;
721 2 sql_result = SQL.BindParameter(
722 1 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER)ptr_param->value.blob.data, 0, &ptr_param->length);
723 1 return odbcstmt_convert_result(sql_result, hstmt);
724 }
725 }
726
727 3 static gate_result_t odbcstmt_set_datetime_param(SQLHSTMT hstmt, SQLUSMALLINT odbc_index, gate_datetime_t const* dt, gate_slotlist_t* param_cache)
728 {
729 3 odbc_param_t* ptr_param = odbc_param_get(param_cache, odbc_index);
730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == ptr_param)
731 {
732 return GATE_RESULT_OUTOFMEMORY;
733 }
734 else
735 {
736 SQLRETURN sql_result;
737 3 SQL_TIMESTAMP_STRUCT* sql_dt = &ptr_param->value.sql_timestamp;
738 3 sql_dt->year = dt->date.year;
739 3 sql_dt->month = dt->date.month;
740 3 sql_dt->day = dt->date.day;
741 3 sql_dt->hour = dt->time.hour;
742 3 sql_dt->minute = dt->time.minute;
743 3 sql_dt->second = dt->time.second;
744 3 sql_dt->fraction = 0;
745 3 ptr_param->length = sizeof(SQL_TIMESTAMP_STRUCT);
746
747
748 3 sql_result = SQL.BindParameter(
749 hstmt, odbc_index, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 0, 0, sql_dt, ptr_param->length, &ptr_param->length);
750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!SQL_SUCCEEDED(sql_result))
751 {
752 /* ODBC Date-time structs are not supported by all drivers, try text-representation: */
753 gate_result_t result;
754 char str[32] = GATE_INIT_EMPTY;
755 gate_size_t len = sizeof(str);
756 result = gate_date_to_string(dt, 0, "{YYYY}-{MM}-{DD} {hh}:{mm}:{ss}", str, &len);
757 if (GATE_SUCCEEDED(result))
758 {
759 return odbcstmt_set_text_param(hstmt, odbc_index, str, len, param_cache);
760 }
761 }
762 3 return odbcstmt_convert_result(sql_result, hstmt);
763 }
764 }
765
766
767 12 static gate_result_t odbcstmt_set_param(gate_data_statement_base_t* self, gate_size_t index, gate_value_t const* value)
768 {
769 12 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
770 12 SQLUSMALLINT odbc_index = (SQLUSMALLINT)(index);
771 12 gate_slotlist_t* ptr_slots = (gate_slotlist_t*)self->native_handles[2];
772 gate_cstrbuffer8_t buffer;
773 12 gate_datetime_t dt = GATE_INIT_EMPTY;
774 12 gate_result_t ret = GATE_RESULT_FAILED;
775
776
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))
777 {
778 return odbcstmt_set_null_param(hstmt, odbc_index, ptr_slots);
779 }
780
781
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)
782 {
783 case GATE_TYPE_BOOL: return odbcstmt_set_int_param(hstmt, odbc_index, value->content.bool_value ? 1 : 0, ptr_slots);
784 1 case GATE_TYPE_I8: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.i8_value, ptr_slots);
785 1 case GATE_TYPE_I16: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.i16_value, ptr_slots);
786 2 case GATE_TYPE_I32: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.i32_value, ptr_slots);
787 case GATE_TYPE_I64: return odbcstmt_set_bigint_param(hstmt, odbc_index, (gate_int32_t)value->content.i64_value, ptr_slots);
788 case GATE_TYPE_UI8: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.ui8_value, ptr_slots);
789 case GATE_TYPE_UI16: return odbcstmt_set_int_param(hstmt, odbc_index, (gate_int32_t)value->content.ui16_value, ptr_slots);
790 case GATE_TYPE_UI32: return odbcstmt_set_bigint_param(hstmt, odbc_index, (gate_int64_t)value->content.ui32_value, ptr_slots);
791 case GATE_TYPE_UI64: return odbcstmt_set_bigint_param(hstmt, odbc_index, (gate_int64_t)value->content.ui64_value, ptr_slots);
792
793 1 case GATE_TYPE_R32: return odbcstmt_set_real_param(hstmt, odbc_index, (gate_real64_t)value->content.r32_value, ptr_slots);
794 case GATE_TYPE_R64: return odbcstmt_set_real_param(hstmt, odbc_index, (gate_real64_t)value->content.r64_value, ptr_slots);
795
796 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);
797
798 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);
799 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);
800
801 1 case GATE_TYPE_WSTR:
802 {
803
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)))
804 {
805 return GATE_RESULT_OUTOFMEMORY;
806 }
807 1 ret = odbcstmt_set_text_param(hstmt, odbc_index, gate_cstrbuffer_get(&buffer), gate_cstrbuffer_length(&buffer), ptr_slots);
808 1 gate_cstrbuffer_destroy(&buffer);
809 1 return ret;
810 }
811 1 case GATE_TYPE_GUID:
812 {
813 1 ret = gate_guid_to_string(&value->content.guid_value, buffer.local_buffer);
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_RETURN_IF_FAILED(ret);
815 1 return odbcstmt_set_text_param(hstmt, odbc_index, buffer.local_buffer, gate_str_length(buffer.local_buffer), ptr_slots);
816 }
817 1 case GATE_TYPE_DATE:
818 {
819 1 dt.date = value->content.date_value;
820 1 return odbcstmt_set_datetime_param(hstmt, odbc_index, &dt, ptr_slots);
821 }
822 1 case GATE_TYPE_DATETIME:
823 {
824 1 return odbcstmt_set_datetime_param(hstmt, odbc_index, &value->content.datetime_value, ptr_slots);
825 }
826 1 case GATE_TYPE_TIME:
827 {
828 1 ret = gate_time_to_datetime(&value->content.time_value, &dt);
829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_RETURN_IF_FAILED(ret);
830 1 return odbcstmt_set_datetime_param(hstmt, odbc_index, &dt, ptr_slots);
831 }
832 case GATE_TYPE_PROPERTY:
833 default:
834 return GATE_RESULT_INCORRECTTYPE;
835 }
836 }
837
838 static gate_result_t odbcstmt_set_named_param(gate_data_statement_base_t* self, gate_string_t const* name, gate_value_t const* value)
839 {
840 /* named parameters are not supported by odbc */
841 return GATE_RESULT_NOTSUPPORTED;
842 }
843
844 3 static gate_result_t odbcstmt_reset(gate_data_statement_base_t* self)
845 {
846 SQLRETURN sql_ret;
847 3 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
848
849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (hstmt == NULL)
850 {
851 return GATE_RESULT_INVALIDSTATE;
852 }
853
854 3 sql_ret = SQL.FreeStmt(hstmt, SQL_RESET_PARAMS);
855
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 switch (sql_ret)
856 {
857 3 case SQL_SUCCESS:
858 case SQL_SUCCESS_WITH_INFO:
859 3 return GATE_RESULT_OK;
860 default:
861 return GATE_RESULT_FAILED;
862 }
863 }
864
865 9 static gate_result_t odbcstmt_execute(gate_data_statement_base_t* self, gate_int32_t* affected_rows)
866 {
867 SQLRETURN sql_ret;
868 9 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
869 9 SQLLEN len_rows = 0;
870
871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (hstmt == NULL)
872 {
873 return GATE_RESULT_INVALIDSTATE;
874 }
875
876 9 sql_ret = SQL.Execute(hstmt);
877
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))
878 {
879 SQLTCHAR sqlState[32] = GATE_INIT_EMPTY;
880 SQLINTEGER native_error_code = 0;
881 SQLTCHAR sqlMsg[1024] = GATE_INIT_EMPTY;
882 SQLSMALLINT sqlMsgLen = 0;
883 SQL.GetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sqlState, &native_error_code, sqlMsg, sizeof(sqlMsg) / sizeof(sqlMsg[0]), &sqlMsgLen);
884 return GATE_RESULT_FAILED;
885 }
886
887 /* success case */
888
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (affected_rows)
889 {
890 9 SQL.RowCount(hstmt, &len_rows);
891 9 *affected_rows = (gate_int32_t)len_rows;
892 }
893 9 return GATE_RESULT_OK;
894 }
895
896 2 static gate_result_t odbcstmt_query(gate_data_statement_base_t* self, gate_data_reader_t** ptr_reader)
897 {
898 SQLRETURN sql_ret;
899 2 SQLHSTMT hstmt = (SQLHSTMT)self->native_handles[1];
900 2 SQLLEN len_rows = 0;
901
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (hstmt == NULL)
903 {
904 return GATE_RESULT_INVALIDSTATE;
905 }
906
907 2 sql_ret = SQL.Execute(hstmt);
908
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))
909 {
910 SQLTCHAR sqlState[32] = GATE_INIT_EMPTY;
911 SQLINTEGER native_error_code = 0;
912 SQLTCHAR sqlMsg[1024] = GATE_INIT_EMPTY;
913 SQLSMALLINT sqlMsgLen = 0;
914 SQL.GetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sqlState, &native_error_code, sqlMsg, sizeof(sqlMsg) / sizeof(sqlMsg[0]), &sqlMsgLen);
915 return GATE_RESULT_FAILED;
916 }
917
918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ptr_reader == NULL)
919 {
920 /* success, reader not required, free unused resources */
921 SQL.FreeStmt(hstmt, SQL_CLOSE);
922 SQL.FreeStmt(hstmt, SQL_DROP);
923 return GATE_RESULT_OK;
924 }
925
926 2 *ptr_reader = gate_data_reader_odbc_create(self, hstmt);
927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (*ptr_reader == NULL)
928 {
929 /* failed to allocate data reader */
930 SQL.FreeStmt(hstmt, SQL_CLOSE);
931 SQL.FreeStmt(hstmt, SQL_DROP);
932 return GATE_RESULT_FAILED;
933 }
934 2 return GATE_RESULT_OK;
935
936 }
937
938
939
940
941
942
943
944
945 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)
946 {
947 11 gate_result_t ret = GATE_RESULT_FAILED;
948 11 SQLHSTMT hstmt = NULL;
949 11 SQLHDBC hdbc = self->native_handles[0];
950 SQLRETURN sql_ret;
951 SQLTCHAR cmd[4096 + 2048 + 1024];
952 11 SQLSMALLINT param_count = 0;
953 gate_size_t cmd_len;
954 gate_data_handles_t handles;
955 11 gate_data_statement_base_t* ptr_stmt_base = NULL;
956
957 do
958 {
959 #if defined(GATE_SYS_WIN)
960 cmd_len = gate_win32_utf8_2_winstr(sql->str, sql->length, (LPTSTR)&cmd[0], sizeof(cmd) / sizeof(cmd[0]));
961 #else
962 11 cmd_len = gate_string_to_buffer(sql, (char*)&cmd[0], sizeof(cmd) / sizeof(cmd[0]));
963 #endif
964
965 11 sql_ret = SQL.AllocStmt(hdbc, &hstmt);
966
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (SQL_SUCCESS != sql_ret)
967 {
968 ret = GATE_RESULT_OUTOFRESOURCES;
969 break;
970 }
971
972 11 sql_ret = SQL.Prepare(hstmt, cmd, (SQLINTEGER)cmd_len);
973
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (SQL_SUCCESS != sql_ret)
974 {
975 ret = GATE_RESULT_FAILED;
976 break;
977 }
978
979 11 gate_mem_clear(&handles[0], sizeof(handles));
980 11 handles[0] = (void*)hdbc;
981 11 handles[1] = (void*)hstmt;
982
983 11 ret = gate_data_statement_base_create(
984 self, handles, sql,
985 &odbcstmt_init,
986 &odbcstmt_close,
987 &odbcstmt_set_param,
988 &odbcstmt_set_named_param,
989 &odbcstmt_reset,
990 &odbcstmt_execute,
991 &odbcstmt_query,
992 &ptr_stmt_base);
993
994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 GATE_BREAK_IF_FAILED(ret);
995
996
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 if (SQL_ERROR != SQL.NumParams(hstmt, &param_count))
997 {
998 11 ptr_stmt_base->param_count = param_count;
999 }
1000
1001 /* success case: */
1002
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (ptr_stmt != NULL)
1003 {
1004 11 *ptr_stmt = (gate_data_statement_t*)ptr_stmt_base;
1005 11 ptr_stmt_base = NULL;
1006 }
1007 11 hstmt = NULL;
1008 11 ret = GATE_RESULT_OK;
1009 } while (0);
1010
1011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ptr_stmt_base != NULL)
1012 {
1013 gate_object_release(ptr_stmt_base);
1014 }
1015
1016
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (hstmt != NULL)
1017 {
1018 SQL.FreeStmt(hstmt, SQL_CLOSE);
1019 SQL.FreeStmt(hstmt, SQL_DROP);
1020 }
1021 11 return ret;
1022 }
1023
1024 2 static gate_result_t gate_data_connection_odbc_init(gate_data_connection_base_t* self)
1025 {
1026 GATE_UNUSED_ARG(self);
1027 2 return GATE_RESULT_OK;
1028 }
1029
1030 2 static void gate_data_connection_odbc_close(gate_data_connection_base_t* self)
1031 {
1032 2 SQLHDBC hdbc = self->native_handles[0];
1033 2 SQLHENV henv = self->native_handles[1];
1034
1035
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (hdbc != NULL)
1036 {
1037 2 SQL.Disconnect(hdbc);
1038 2 SQL.FreeConnect(hdbc);
1039 }
1040
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (henv != NULL)
1041 {
1042 2 SQL.FreeEnv(henv);
1043 }
1044 2 gate_mem_clear(self->native_handles, sizeof(self->native_handles));
1045 2 }
1046
1047
1048
1049 4 gate_result_t gate_data_adapter_odbc_create(gate_string_t const* path, gate_enumint_t flags, gate_data_connection_t** ptr_connection)
1050 {
1051 4 gate_result_t ret = GATE_RESULT_OK;
1052 SQLTCHAR str_connection[4096];
1053 gate_size_t str_connection_len;
1054 4 SQLTCHAR* str_user = NULL;
1055 4 gate_size_t str_user_len = 0;
1056 4 SQLTCHAR* str_pass = NULL;
1057 4 gate_size_t str_pass_len = 0;
1058 4 SQLHENV henv = NULL;
1059 4 SQLHDBC hdbc = NULL;
1060 SQLRETURN sql_ret;
1061 4 gate_data_handles_t handles = GATE_INIT_EMPTY;
1062
1063 do
1064 {
1065 4 ret = load_odbc_functions();
1066
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(ret);
1067
1068 #if defined(GATE_SYS_WIN)
1069 str_connection_len = gate_win32_utf8_2_winstr(path->str, path->length, (LPTSTR)&str_connection[0], sizeof(str_connection) / sizeof(str_connection[0]));
1070 #else
1071 4 str_connection_len = gate_string_to_buffer(path, (char*)&str_connection[0], sizeof(str_connection) / sizeof(str_connection[0]));
1072 #endif
1073
1074
1075 4 sql_ret = SQL.AllocEnv(&henv);
1076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (SQL_SUCCESS != sql_ret)
1077 {
1078 ret = GATE_RESULT_OUTOFRESOURCES;
1079 break;
1080 }
1081
1082 4 sql_ret = SQL.AllocConnect(henv, &hdbc);
1083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (SQL_SUCCESS != sql_ret)
1084 {
1085 ret = GATE_RESULT_OUTOFRESOURCES;
1086 break;
1087 }
1088
1089 12 sql_ret = SQL.Connect(hdbc, str_connection, (SQLSMALLINT)str_connection_len,
1090 4 str_user, (SQLSMALLINT)str_user_len, str_pass, (SQLSMALLINT)str_pass_len);
1091
1092
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))
1093 {
1094 SQLTCHAR state_msg[1024];
1095 2 SQLINTEGER native_error = 0;
1096 SQLTCHAR error_msg[1024];
1097 2 SQLSMALLINT error_msg_used = 0;
1098 2 SQL.GetDiagRec(SQL_HANDLE_DBC, hdbc, 1, state_msg, &native_error, error_msg, 1024, &error_msg_used);
1099 2 ret = GATE_RESULT_FAILED;
1100 2 break;
1101 }
1102
1103 2 handles[0] = (void*)hdbc;
1104 2 handles[1] = (void*)henv;
1105 2 ret = gate_data_connection_base_create(
1106 handles,
1107 &gate_data_connection_odbc_init,
1108 &gate_data_connection_odbc_close,
1109 &gate_data_connection_odbc_create_statement,
1110 ptr_connection);
1111
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(ret))
1112 {
1113 2 hdbc = NULL;
1114 2 henv = NULL;
1115 }
1116 } while (0);
1117
1118
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (hdbc)
1119 {
1120 2 SQL.Disconnect(hdbc);
1121 2 SQL.FreeConnect(hdbc);
1122 }
1123
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (henv)
1124 {
1125 2 SQL.FreeEnv(henv);
1126 }
1127 4 return ret;
1128 }
1129
1130 #else /* GATE_DATA_ODBC_IMPL */
1131
1132 gate_result_t gate_data_adapter_odbc_create(gate_string_t const* path, gate_enumint_t flags, gate_data_connection_t** ptr_connection)
1133 {
1134 (void)path;
1135 (void)flags;
1136 (void)ptr_connection;
1137 return GATE_RESULT_NOTIMPLEMENTED;
1138 }
1139
1140 #endif
1141