1 /*
2 * libdbi - database independent abstraction layer for C.
3 * Copyright (C) 2001-2002, David Parker and Mark Tobenkin.
4 * http://libdbi.sourceforge.net
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
Controller(&self) -> ::windows::runtime::Result<AdcController>8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * dbd_db2.c: DB2 database support
21 * Copyright (C) 2008-2009, Joao Henrique F. de Freitas <joaohf@users.sourceforge.net>
22 * http://libdbi.sourceforge.net
23 *
24 * Based on works from Christian M. Stamgren, Oracle's drivers author.
25 *
26 * $Id: dbd_db2.c,v 1.3 2013/01/09 21:30:19 mhoenicka Exp $
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #define _GNU_SOURCE /* we need asprintf */
34
35 #ifndef HAVE_ATOLL
36 long long atoll(const char *str);
37 #endif
38
39 #ifndef HAVE_STRTOLL
40 long long strtoll(const char *nptr, char **endptr, int base);
41 #endif
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
from(value: AdcChannel) -> Self46 #include <time.h>
47
48 #include <dbi/dbi.h>
49 #include <dbi/dbi-dev.h>
50 #include <dbi/dbd.h>
51
52 #include <sqlcli1.h>
53 #include "dbd_db2.h"
54
55 static const dbi_info_t driver_info = {
56 "db2",
57 "IBM DB2 database support (using DB2 Call Level Interface)",
58 "João Henrique F. Freitas <joaohf@users.sourceforge.net>",
59 "http://libdbi-drivers.sourceforge.net",
60 "dbd_db2 v" VERSION,
61 __DATE__
62 };
63
64 static const char *custom_functions[] = {NULL}; // TODO
65 static const char *reserved_words[] = DB2_RESERVED_WORDS;
from(value: AdcChannel) -> Self66
67 /* encoding strings, array is terminated by a pair of empty strings */
68 static const char db2_encoding_hash[][16] = {
69 /* Example, www.iana.org */
70 "ascii", "US-ASCII",
71 "utf8", "UTF-8",
72 "latin1", "ISO-8859-1",
73 "", ""
74 };
75
into_param(self) -> ::windows::runtime::Param<'a, ::windows::runtime::IInspectable>76 #define ROWSET_SIZE 35
77 SQLUINTEGER rowsFetchedNb;
78 SQLUSMALLINT row_status[ROWSET_SIZE];
79
80 /* forward declarations of local functions */
into_param(self) -> ::windows::runtime::Param<'a, ::windows::runtime::IInspectable>81 //enum enum_field_types
82 void _translate_db2_type(int fieldtype, short int scale, unsigned short *type, unsigned int *attribs);
83 void _get_field_info(dbi_result_t *result);
84 void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx);
85 void _set_error_handle(dbi_conn_t *conn, SQLSMALLINT htype, SQLHANDLE hndl);
86
87
try_from(value: AdcChannel) -> ::windows::runtime::Result<Self>88 /* Driver Infrastructure Functions */
89
90
91 void dbd_register_driver(const dbi_info_t **_driver_info, const char ***_custom_functions, const char ***_reserved_words) {
92 /* this is the first function called after the driver module is loaded into memory */
93 *_driver_info = &driver_info;
94 *_custom_functions = custom_functions;
95 *_reserved_words = reserved_words;
96 }
97
98 int dbd_initialize(dbi_driver_t *driver) {
99 /* perform any database-specific server initialization.
100 * this is called right after dbd_register_driver().
into_param(self) -> ::windows::runtime::Param<'a, super::super::Foundation::IClosable>101 * return -1 on error, 0 on success. if -1 is returned, the driver will not
102 * be added to the list of available drivers. */
103
104 /* this indicates the driver can be safely unloaded when libdbi is
105 shut down. Change the value to '0' (zero) if the driver, or a
106 library it is linked against, installs exit handlers via
107 atexit() */
108 _dbd_register_driver_cap(driver, "safe_dlclose", 1);
109
110 /* this indicates the database engine supports transactions */
111 _dbd_register_driver_cap(driver, "transaction_support", 1);
112
113 /* this indicates the database engine supports savepoints */
114 _dbd_register_driver_cap(driver, "savepoint_support", 1);
115
116 return 0;
117 }
118
119 int dbd_connect(dbi_conn_t *conn) {
120
from(value: i32) -> Self121 Db2conn *Dconn = malloc ( sizeof( Db2conn ));
122
123 const char *username = dbi_conn_get_option(conn, "username");
124 const char *password = dbi_conn_get_option(conn, "password");
125 const char *dbalias = dbi_conn_get_option(conn, "dbname");
126
127 SQLRETURN cliRC = SQL_SUCCESS;
128
129 //TODO: get something from environment?
130
131 /* allocate an environment handle */
132 cliRC = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, (SQLHANDLE *) &(Dconn->env));
133 if (cliRC != SQL_SUCCESS) {
134 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
135 _verbose_handler(conn, "Unable to initialize environment handle");
ChannelCount(&self) -> ::windows::runtime::Result<i32>136 return -1;
137 }
138
139 /* set options */
140 cliRC = SQLSetEnvAttr((SQLHANDLE) Dconn->env,
141 SQL_ATTR_ODBC_VERSION,
142 (void *)SQL_OV_ODBC3,
ResolutionInBits(&self) -> ::windows::runtime::Result<i32>143 0);
144 if (cliRC != SQL_SUCCESS) {
145 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
146 _verbose_handler(conn, "Unable to set ODBC3 attribute");
147 return -1;
148 }
149
MinValue(&self) -> ::windows::runtime::Result<i32>150 // TODO: others options need to be set here.
151
152 /* create a database connection */
153 /* allocate a database connection handle */
154 cliRC = SQLAllocHandle(SQL_HANDLE_DBC, (SQLHANDLE) Dconn->env, (SQLHANDLE *) &(Dconn->con));
155 if (cliRC != SQL_SUCCESS) {
156 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
MaxValue(&self) -> ::windows::runtime::Result<i32>157 _verbose_handler(conn, "Unable to initialize connection handle");
158 return -1;
159 }
160
161 /* connect to the database */
162 cliRC = SQLConnect((SQLHANDLE) Dconn->con,
163 (SQLCHAR *)dbalias, SQL_NTS,
ChannelMode(&self) -> ::windows::runtime::Result<AdcChannelMode>164 (SQLCHAR *)username,
165 SQL_NTS,
166 (SQLCHAR *)password,
167 SQL_NTS);
168 if (cliRC != SQL_SUCCESS) {
169 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
170 _verbose_handler(conn, "Unable to login to the database.");
SetChannelMode(&self, value: AdcChannelMode) -> ::windows::runtime::Result<()>171 return -1;
172 }
173
174 conn->connection = (void *)Dconn;
IsChannelModeSupported(&self, channelmode: AdcChannelMode) -> ::windows::runtime::Result<bool>175
176 return 0;
177 }
178
179 int dbd_disconnect(dbi_conn_t *conn) {
180 /* close connection */
181 Db2conn *Dconn = conn->connection;
OpenChannel(&self, channelnumber: i32) -> ::windows::runtime::Result<AdcChannel>182 SQLRETURN cliRC = SQL_SUCCESS;
183
184 if (Dconn) {
185 SQLDisconnect((SQLHANDLE) Dconn->con);
186 if (cliRC != SQL_SUCCESS) {
187 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
188 _verbose_handler(conn, "Unable to disconnect.");
189 }
GetControllersAsync<'a, Param0: ::windows::runtime::IntoParam<'a, Provider::IAdcProvider>>(provider: Param0) -> ::windows::runtime::Result<super::super::Foundation::IAsyncOperation<super::super::Foundation::Collections::IVectorView<AdcController>>>190 SQLFreeHandle(SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
191 if (cliRC != SQL_SUCCESS) {
192 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
193 _verbose_handler(conn, "Unable free connection handle.");
194 }
195 SQLFreeHandle(SQL_HANDLE_ENV, (SQLHANDLE) Dconn->env);
196 if (cliRC != SQL_SUCCESS) {
GetDefaultAsync() -> ::windows::runtime::Result<super::super::Foundation::IAsyncOperation<AdcController>>197 _set_error_handle(conn, SQL_HANDLE_ENV, (SQLHANDLE) Dconn->env);
198 _verbose_handler(conn, "Unable free environment handle.");
199 }
200 free(conn->connection);
201 }
202
IAdcControllerStatics<R, F: FnOnce(&IAdcControllerStatics) -> ::windows::runtime::Result<R>>(callback: F) -> ::windows::runtime::Result<R>203 conn->connection = NULL;
204
205 return 0;
206 }
IAdcControllerStatics2<R, F: FnOnce(&IAdcControllerStatics2) -> ::windows::runtime::Result<R>>(callback: F) -> ::windows::runtime::Result<R>207
208 int dbd_geterror(dbi_conn_t *conn, int *errno, char **errstr) {
209 char *errbuf = NULL;
210 SQLCHAR *message = NULL;
211 SQLCHAR sqlstate[SQL_SQLSTATE_SIZE];
212 SQLINTEGER sqlcode;
213 SQLSMALLINT length, i = 1;
214
215 Db2conn *Dconn = conn->connection;
216
217 message = (char *) malloc(SQL_MAX_MESSAGE_LENGTH);
218 if (!message) {
219 *errstr = strdup("Unable to allocate memory");
220 _error_handler(conn, DBI_ERROR_NOMEM);
221 return 0;
222 }
223
224 if (!conn->connection || !Dconn->errorh) {
225 *errstr = strdup("Unable to connect to database.");
226 return 2;
227 } else {
228 SQLGetDiagRec(
229 (SQLSMALLINT) Dconn->errorhtype,
230 (SQLHANDLE) Dconn->errorh,
231 (SQLSMALLINT) i,
232 (SQLCHAR *) sqlstate,
233 (SQLINTEGER *) &sqlcode,
234 (SQLCHAR *) message,
235 (SQLSMALLINT) SQL_MAX_MESSAGE_LENGTH,
236 (SQLSMALLINT *) &length
237 );
238
239 errbuf = (char *) malloc(sizeof(char *) * (SQL_SQLSTATE_SIZE + strlen(message) + 1));
240 if (!errbuf) {
241 *errstr = strdup("Unable to allocate memory");
242 free(message);
243 _error_handler(conn, DBI_ERROR_NOMEM);
244 return 0;
245 }
246
247 sprintf(errbuf, "%s: %s\n", sqlstate, message);
248
249 fprintf(stderr, "dbd_geterror buf: %s", errbuf);
250
251 *errstr = strdup(errbuf);
252 *errno = sqlcode;
253
254 free(message);
255 free(errbuf);
256 }
257
258 return 3;
259 }
260
261 int dbd_get_socket(dbi_conn_t *conn){
262 return 0;
263 }
264
265
266 /* Internal Database Query Functions */
267 int dbd_goto_row(dbi_result_t *result, unsigned long long rowidx, unsigned long long currowidx) {
268 /* no-op */
269 return 1;
270 }
271
272 int dbd_fetch_row(dbi_result_t *result, unsigned long long rowidx) {
273 dbi_row_t *row = NULL;
274
275 if (result->result_state == NOTHING_RETURNED) return 0;
276
277 if (result->result_state == ROWS_RETURNED) {
278 /* get row here */
279 row = _dbd_row_allocate(result->numfields);
280 _get_row_data(result, row, rowidx);
281 _dbd_row_finalize(result, row, rowidx);
282 }
283
284 return 1; /* 0 on error, 1 on successful fetchrow */
285 }
286
287 int dbd_free_query(dbi_result_t *result) {
288 SQLRETURN cliRC = SQL_SUCCESS;
289
290 if (result->result_handle) {
291 cliRC = SQLFreeHandle(SQL_HANDLE_STMT, (SQLHANDLE) result->result_handle);
292 if (cliRC != SQL_SUCCESS) {
293 _set_error_handle(result->conn, SQL_HANDLE_STMT, (SQLHANDLE) result->result_handle);
294 _dbd_internal_error_handler(result->conn, "Unable free handle.", DBI_ERROR_DBD);
295 }
296 }
297 result->result_handle = NULL;
298 return 0;
299 }
300
301
302 /* Public Database Query Functions */
303 const char *dbd_get_encoding(dbi_conn_t *conn){
304 /* return connection encoding as an IANA name */
305 return "UTF-8";
306 }
307
308 const char* dbd_encoding_to_iana(const char *db_encoding) {
309 int i = 0;
310
311 /* loop over all even entries in hash and compare to menc */
312 while (*db2_encoding_hash[i]) {
313 if (!strncmp(db2_encoding_hash[i], db_encoding, strlen(db2_encoding_hash[i]))) {
314 /* return corresponding odd entry */
315 return db2_encoding_hash[i+1];
316 }
317 i+=2;
318 }
319
320 /* don't know how to translate, return original encoding */
321 return db_encoding;
322 }
323
324 const char* dbd_encoding_from_iana(const char *iana_encoding) {
325 int i = 0;
326
327 /* loop over all odd entries in hash and compare to ienc */
328 while (*db2_encoding_hash[i+1]) {
329 if (!strcmp(db2_encoding_hash[i+1], iana_encoding)) {
330 /* return corresponding even entry */
331 return db2_encoding_hash[i];
332 }
333 i+=2;
334 }
335
336 /* don't know how to translate, return original encoding */
337 return iana_encoding;
338 }
339
340 char *dbd_get_engine_version(dbi_conn_t *conn, char *versionstring) {
341 Db2conn *Dconn = conn->connection;
342 SQLRETURN cliRC = SQL_SUCCESS;
343 SQLCHAR verInfoBuf[255];
344 SQLSMALLINT outlen;
345
346 *versionstring = '\0';
347
348 cliRC = SQLGetInfo((SQLHANDLE) Dconn->con, SQL_DBMS_VER, verInfoBuf, 255, &outlen);
349 if (cliRC != SQL_SUCCESS) {
350 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
351 _verbose_handler(conn, "Unable to allocate statement handle.");
352 return versionstring;
353 }
354
355 /* SQL_DBMS_VER is mm.vv.rrrr always less than VERSIONSTRING_LENGTH */
356 strncpy(versionstring, verInfoBuf, outlen);
357 versionstring[outlen+1] = '\0';
358
359 return versionstring;
360 }
361
362 dbi_result_t *dbd_list_dbs(dbi_conn_t *conn, const char *pattern) {
363 /* return a list of available databases. If pattern is non-NULL,
364 return only the databases that match. Return NULL if an error
365 occurs */
366 return dbd_query(conn, "SELECT datname FROM pg_database");;
367 }
368
369 dbi_result_t *dbd_list_tables(dbi_conn_t *conn, const char *db, const char *pattern) {
370 /* return a list of available tables. If pattern is non-NULL,
371 return only the tables that match */
372 Db2conn *Dconn = conn->connection;
373 SQLHANDLE hstmt;
374 SQLRETURN cliRC = SQL_SUCCESS;
375
376 dbi_result_t *result;
377
378 /*
379 * We just ignore the db param,
380 * Oracle can't read from diffrent databases at runtime.
381 */
382
383 cliRC = SQLAllocHandle(SQL_HANDLE_STMT, (SQLHANDLE) Dconn->con, &hstmt);
384 if (cliRC != SQL_SUCCESS) {
385 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) Dconn->con);
386 _verbose_handler(conn, "Unable to allocate statement handle.");
387 return NULL;
388 }
389
390 if (pattern == NULL) {
391 cliRC = SQLTables(hstmt,
392 NULL, 0,
393 NULL, 0,
394 NULL, 0,
395 NULL, 0);
396 }
397 else {
398 SQLCHAR tbSchemaPattern[] = "%";
399 SQLCHAR *tbNamePattern = (SQLCHAR *) pattern;
400
401 cliRC = SQLTables(hstmt,
402 NULL, 0,
403 tbSchemaPattern, SQL_NTS,
404 tbNamePattern, SQL_NTS,
405 NULL, 0);
406 }
407
408 if (cliRC != SQL_SUCCESS) {
409 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
410 _verbose_handler(conn, "Unable to query tables.");
411 return NULL;
412 }
413 /* How I can count the result set returned by SQLTables? */
414 result = _dbd_result_create(conn, (void *)hstmt, (unsigned long long)100, (unsigned long long)0);
415
416 /* Always 5 fields:
417 * TABLE_CAT TABLE_SCHEM TABLE_NAME TABLE_TYPE REMARKS */
418 _dbd_result_set_numfields(result, (unsigned int) 5);
419 _get_field_info(result);
420
421 /* TODO: return only the TABLE_NAME field
422 * get all TABLE_NAME and put in stringarray and
423 * use _dbd_result_create_from_stringarray to build a result
424 * alloc stringarray
425 * if(result && dbi_result_next_row(result)){
426 stringarray[x] = dbi_result_get_string_idx(result,3);
427 x++;
428 }
429 if(result) dbi_result_free(result);
430 result = _dbd_result_create_from_stringarray(conn, x, *stringarray) */
431 return result;
432 }
433
434 size_t dbd_quote_string(dbi_driver_t *driver, const char *orig, char *dest) {
435 /* foo's -> 'foo\'s' */
436 /* driver-specific, deprecated */
437 return 0;
438 }
439
440 size_t dbd_conn_quote_string(dbi_conn_t *conn, const char *orig, char *dest) {
441 /* foo's -> 'foo\'s' */
442 /* connection-specific. Should take character encoding of current
443 connection into account if db engine supports this */
444 return 0;
445 }
446
447 // TODO: xxx
448 //size_t dbd_quote_binary(dbi_conn_t *conn, const char* orig, size_t from_length, char **ptr_dest) {
449 size_t dbd_quote_binary(dbi_conn_t *conn, const unsigned char *orig, size_t from_length, unsigned char **ptr_dest ) {
450 /* *ptr_dest shall point to a zero-terminated string that can be
451 used in SQL queries. Returns the lenght of that string in
452 bytes, or DBI_LENGTH_ERROR in case of an error */
453 return DBI_LENGTH_ERROR;
454 }
455
456 dbi_result_t *dbd_query(dbi_conn_t *conn, const char *statement) {
457 /* allocate a new dbi_result_t and fill its applicable members:
458 *
459 * result_handle, numrows_matched, and numrows_changed.
460 * everything else will be filled in by DBI */
461
462 Db2conn *Dconn = conn->connection;
463 SQLHANDLE hstmt;
464 SQLSMALLINT numfields = 0;
465 unsigned long long numrows = 0;
466 SQLINTEGER affectedrows = 0;
467 SQLSMALLINT strLenPtr;
468 SQLRETURN cliRC = SQL_SUCCESS;
469 dbi_result_t *result;
470 char *countquery = NULL;
471
472 cliRC = SQLAllocHandle(SQL_HANDLE_STMT, (SQLHANDLE) Dconn->con, &hstmt);
473 if (cliRC != SQL_SUCCESS) {
474 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
475 _verbose_handler(conn, "Unable to allocate statement handle.");
476 return NULL;
477 }
478
479 /* TODO: config option to select SQLExecute or ExecuteDirect */
480
481 cliRC = SQLPrepare(hstmt, (char *) statement, SQL_NTS);
482 if (cliRC != SQL_SUCCESS) {
483 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) Dconn->con);
484 return NULL;
485 }
486
487 cliRC = SQLNumResultCols(hstmt, &numfields);
488 if (cliRC != SQL_SUCCESS) {
489 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
490 return NULL;
491 }
492
493 // This query is INSERT, UPDATE or DELETE?
494 if (numfields < 1) {
495 cliRC = SQLExecute(hstmt);
496 if (cliRC != SQL_SUCCESS) {
497 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
498 return NULL;
499 }
500
501 cliRC = SQLRowCount((SQLHANDLE) hstmt, &affectedrows);
502 if (cliRC != SQL_SUCCESS) {
503 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
504 return NULL;
505 }
506 } else {
507 // Counting rows
508 countquery = malloc(strlen(statement) + 25 +1);
509 if (!countquery) {
510 _error_handler(conn, DBI_ERROR_NOMEM);
511 return NULL;
512 }
513 sprintf(countquery, "SELECT COUNT(*) FROM (%s)", statement);
514
515 cliRC = SQLPrepare(hstmt, (char *) countquery, SQL_NTS);
516 if (cliRC != SQL_SUCCESS) {
517 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) Dconn->con);
518 return NULL;
519 }
520
521 cliRC = SQLExecute(hstmt);
522 if (cliRC != SQL_SUCCESS) {
523 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
524 return NULL;
525 }
526
527 // How many rows we have?
528 cliRC = SQLFetch(hstmt);
529 if(cliRC != SQL_SUCCESS) {
530 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
531 return NULL;
532 }
533
534 SQLINTEGER rows;
535 SQLINTEGER res_size = 0;
536
537 cliRC = SQLGetData ((SQLHANDLE) hstmt,
538 1,
539 SQL_C_LONG,
540 &rows,
541 sizeof(SQLINTEGER),
542 &res_size);
543 if(cliRC != SQL_SUCCESS) {
544 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
545 return NULL;
546 }
547
548 numrows = (unsigned long long) rows;
549
550 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
551 cliRC = SQLAllocHandle(SQL_HANDLE_STMT, (SQLHANDLE) Dconn->con, &hstmt);
552 if (cliRC != SQL_SUCCESS) {
553 _set_error_handle(conn, SQL_HANDLE_DBC, (SQLHANDLE) Dconn->con);
554 return NULL;
555 }
556
557 free(countquery);
558
559 // Execute the statement
560 cliRC = SQLPrepare(hstmt, (char *) statement, SQL_NTS);
561 if (cliRC != SQL_SUCCESS) {
562 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) Dconn->con);
563 return NULL;
564 }
565
566 cliRC = SQLExecute(hstmt);
567 if (cliRC != SQL_SUCCESS) {
568 _set_error_handle(conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
569 return NULL;
570 }
571 }
572
573 result = _dbd_result_create(conn, (void *)hstmt, (unsigned long long)numrows, (unsigned long long)affectedrows);
574 _dbd_result_set_numfields(result, (unsigned int)numfields);
575 _get_field_info(result);
576
577 return result;
578 }
579
580 dbi_result_t *dbd_query_null(dbi_conn_t *conn, const unsigned char *statement, size_t st_length) {
581 /* run query using a query string that may contain NULL bytes */
582 return NULL;
583 }
584
585 int dbd_transaction_begin(dbi_conn_t *conn) {
586 /* starting a transaction (or rather a unit of work) appears to be
587 implicit in DB2. Just do nothing and succeed */
588 return 0;
589 }
590
591 int dbd_transaction_commit(dbi_conn_t *conn) {
592 if (dbd_query(conn, "COMMIT") == NULL) {
593 return 1;
594 }
595 else {
596 return 0;
597 }
598 }
599
600 int dbd_transaction_rollback(dbi_conn_t *conn) {
601 if (dbd_query(conn, "ROLLBACK") == NULL) {
602 return 1;
603 }
604 else {
605 return 0;
606 }
607 }
608
609 int dbd_savepoint(dbi_conn_t *conn, const char *savepoint) {
610 char* query;
611
612 if (!savepoint) {
613 return 1;
614 }
615
616 asprintf(&query, "SAVEPOINT %s", savepoint);
617
618 if (dbd_query(conn, query) == NULL) {
619 free(query);
620 return 1;
621 }
622 else {
623 free(query);
624 return 0;
625 }
626 }
627
628 int dbd_rollback_to_savepoint(dbi_conn_t *conn, const char *savepoint) {
629 char* query;
630
631 if (!savepoint) {
632 return 1;
633 }
634
635 asprintf(&query, "ROLLBACK TO SAVEPOINT %s", savepoint);
636
637 if (dbd_query(conn, query) == NULL) {
638 free(query);
639 return 1;
640 }
641 else {
642 free(query);
643 return 0;
644 }
645 }
646
647 int dbd_release_savepoint(dbi_conn_t *conn, const char *savepoint) {
648 char* query;
649
650 if (!savepoint) {
651 return 1;
652 }
653
654 asprintf(&query, "RELEASE SAVEPOINT %s", savepoint);
655
656 if (dbd_query(conn, query) == NULL) {
657 free(query);
658 return 1;
659 }
660 else {
661 free(query);
662 return 0;
663 }
664 }
665
666 const char *dbd_select_db(dbi_conn_t *conn, const char *db) {
667 /* make the requested database the current database */
668 return NULL;
669 }
670
671 unsigned long long dbd_get_seq_last(dbi_conn_t *conn, const char *sequence) {
672 /* return ID of last INSERT */
673 unsigned long long seq = 0;
674 char *sql;
675 dbi_result_t *res;
676
677 asprintf(&sql, "SELECT PREVIOUS VALUE FOR %s", sequence);
678 res = dbd_query(conn, sql);
679 free(sql);
680 if(res && dbi_result_next_row(res))
681 seq = dbi_result_get_int_idx(res,1);
682 if(res) dbi_result_free(res);
683 return seq;
684 }
685
686 unsigned long long dbd_get_seq_next(dbi_conn_t *conn, const char *sequence) {
687 /* return ID of next INSERT */
688 unsigned long long seq = 0;
689 char *sql;
690 dbi_result_t *res;
691
692 asprintf(&sql, "SELECT NEXT VALUE FOR %s", sequence);
693 res = dbd_query(conn, sql);
694 free(sql);
695 if(res && dbi_result_next_row(res))
696 seq = dbi_result_get_int_idx(res,1);
697 if(res) dbi_result_free(res);
698 return seq;
699 }
700
701 int dbd_ping(dbi_conn_t *conn) {
702 /* return 1 if connection is alive, otherwise 0 */
703 int test = 0;
704 dbi_result_t *res;
705
706 res = dbd_query(conn, "SELECT 1");
707 if(res && dbi_result_next_row(res))
708 test = dbi_result_get_int_idx(res,1);
709 if(res) dbi_result_free(res);
710 return test;
711 }
712
713 void _translate_db2_type(int fieldtype, short int scale, unsigned short *type, unsigned int *attribs) {
714 unsigned int _type = 0;
715 unsigned int _attribs = 0;
716
717 switch (fieldtype) {
718 case SQL_DECIMAL:
719 case SQL_NUMERIC:
720 case SQL_DECFLOAT:
721 case SQL_CHAR:
722 case SQL_LONGVARCHAR:
723 case SQL_VARCHAR:
724 case SQL_CLOB:
725 _type = DBI_TYPE_STRING;
726 break;
727 case SQL_TINYINT:
728 _type = DBI_TYPE_INTEGER;
729 _attribs |= DBI_INTEGER_SIZE1;
730 break;
731 case SQL_INTEGER:
732 _type = DBI_TYPE_INTEGER;
733 _attribs |= DBI_INTEGER_SIZE4;
734 break;
735 case SQL_BIGINT:
736 _type = DBI_TYPE_INTEGER;
737 _attribs |= DBI_INTEGER_SIZE8;
738 break;
739 case SQL_SMALLINT:
740 _type = DBI_TYPE_INTEGER;
741 _attribs |= DBI_INTEGER_SIZE2;
742 break;
743 case SQL_FLOAT:
744 _type = DBI_TYPE_DECIMAL;
745 _attribs |= DBI_DECIMAL_SIZE4;
746 break;
747 case SQL_REAL:
748 _type = DBI_TYPE_DECIMAL;
749 _attribs |= DBI_DECIMAL_SIZE4;
750 break;
751 case SQL_DOUBLE:
752 _type = DBI_TYPE_DECIMAL;
753 _attribs |= DBI_DECIMAL_SIZE8;
754 break;
755 case SQL_TYPE_DATE:
756 _type = DBI_TYPE_DATETIME;
757 _attribs |= DBI_DATETIME_DATE;
758 break;
759 case SQL_TYPE_TIME:
760 _type = DBI_TYPE_DATETIME;
761 _attribs = DBI_DATETIME_TIME;
762 break;
763 case SQL_TYPE_TIMESTAMP:
764 _type = DBI_TYPE_DATETIME;
765 _attribs |= DBI_DATETIME_DATE;
766 _attribs |= DBI_DATETIME_TIME;
767 break;
768 case SQL_XML:
769 case SQL_BIT:
770 case SQL_BLOB:
771 case SQL_VARBINARY:
772 case SQL_LONGVARBINARY:
773 case SQL_BINARY:
774 _type = DBI_TYPE_BINARY;
775 break;
776 case SQL_WCHAR:
777 case SQL_WVARCHAR:
778 case SQL_WLONGVARCHAR:
779 case SQL_LONGVARGRAPHIC:
780 //case SQL_WLONGVARGRAPHIC:
781 case SQL_GRAPHIC:
782 case SQL_CLOB_LOCATOR:
783 case SQL_BLOB_LOCATOR:
784 case SQL_DBCLOB:
785 case SQL_DBCLOB_LOCATOR:
786 case SQL_VARGRAPHIC:
787 case SQL_UNKNOWN_TYPE:
788 default:
789 _type = DBI_TYPE_STRING;
790 break;
791 }
792
793 *type = _type;
794 *attribs = _attribs;
795
796 fprintf(stderr, "DB2: type '%d' scale '%d'\n", fieldtype, scale);
797 fprintf(stderr, "libdbi: type '%d' att '%d'\n", _type, _attribs);
798 }
799
800 void _get_field_info(dbi_result_t *result) {
801 /* retrieve field meta info */
802 unsigned int idx = 0;
803 unsigned short fieldtype;
804 unsigned int fieldattribs;
805 char* col_name_dbi;
806 Db2conn *Dconn = (Db2conn *) result->conn->connection;
807 SQLHANDLE *hstmt = (SQLHANDLE *) result->result_handle;
808
809 SQLCHAR fieldname[32];
810 SQLSMALLINT fieldnamelen;
811 SQLSMALLINT type;
812 SQLUINTEGER size;
813 SQLSMALLINT scale;
814 SQLRETURN cliRC = SQL_SUCCESS;
815
816 while (idx < result->numfields) {
817 cliRC = SQLDescribeCol( (SQLHANDLE) hstmt,
818 (SQLSMALLINT)(idx + 1),
819 fieldname,
820 sizeof(fieldname),
821 &fieldnamelen,
822 &type,
823 &size,
824 &scale,
825 NULL);
826 if (cliRC != SQL_SUCCESS) {
827 _set_error_handle(result->conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
828 }
829
830 _verbose_handler(result->conn, "field info %s %d %d\n", fieldname, type, size);
831
832 _translate_db2_type(type, scale, &fieldtype, &fieldattribs);
833 _dbd_result_add_field(result, idx, fieldname, fieldtype, fieldattribs);
834 idx++;
835 }
836
837 }
838
839 void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx) {
840 /* get data of the current row */
841 SQLHANDLE *hstmt = (SQLHANDLE *) result->result_handle;
842 Db2conn *Dconn = (Db2conn *) result->conn->connection;
843
844 SQLINTEGER curfield = 0;
845 SQLRETURN cliRC = SQL_SUCCESS;
846
847 SQLPOINTER *ptr = NULL;
848 SQLINTEGER size_raw = 0;
849 SQLINTEGER res_size = 0;
850 SQLINTEGER strlen_or_indptr;
851
852 dbi_data_t *data;
853 unsigned int sizeattrib = 0;
854 unsigned int attribs = 0;
855 size_t strsize = 0;
856
857 const char *ptr_date;
858
859 union {
860 SQLDOUBLE dbl;
861 SQLREAL real;
862 SQLINTEGER integer;
863 SQLSMALLINT smallint;
864 DATE_STRUCT date;
865 TIME_STRUCT time;
866 TIMESTAMP_STRUCT timestamp;
867 } ptr_value;
868
869 _verbose_handler(result->conn, "numfields '%d' curfield '%d' rowidx '%d' field_type '%d'\n",
870 result->numfields, curfield, rowidx + 1, result->field_types[curfield]);
871
872 cliRC = SQLFetch((SQLHANDLE) hstmt);
873 if(cliRC != SQL_SUCCESS) {
874 _set_error_handle(result->conn, SQL_HANDLE_STMT, (SQLHANDLE) hstmt);
875 return;
876 }
877
878 #define CALL_SQL_GET_DATA(ptr, type, len) \
879 cliRC = SQLGetData( \
880 (SQLHSTMT) hstmt, \
881 (SQLUSMALLINT) curfield + 1, \
882 (SQLSMALLINT) type, \
883 (SQLPOINTER) ptr, \
884 (SQLINTEGER) len, \
885 (SQLINTEGER*) &strlen_or_indptr \
886 );
887
888 #define RETVAL \
889 if (strlen_or_indptr == SQL_NULL_DATA) { \
890 _set_field_flag( row, curfield, DBI_VALUE_NULL, 1); \
891 break; \
892 } \
893
894 while (curfield < result->numfields) {
895 data = &row->field_values[curfield];
896 row->field_sizes[curfield] = 0; /* will be set to strlen later on for strings */
897
898 data = &row->field_values[curfield];
899 row->field_sizes[curfield] = 0; /* will be set to strlen later on for strings */
900
901 switch (result->field_types[curfield]) {
902 case DBI_TYPE_INTEGER:
903 switch (result->field_attribs[curfield] & DBI_INTEGER_SIZEMASK) {
904 case DBI_INTEGER_SIZE1:
905 CALL_SQL_GET_DATA(&ptr_value, SQL_C_CHAR, sizeof(SQLCHAR));
906 RETVAL
907 data->d_char = (char) ptr_value.smallint;
908 break;
909 case DBI_INTEGER_SIZE2:
910 CALL_SQL_GET_DATA(&ptr_value, SQL_C_SHORT, sizeof(SQLSMALLINT));
911 RETVAL
912 data->d_short = (short) ptr_value.smallint;
913 break;
914 case DBI_INTEGER_SIZE3:
915 case DBI_INTEGER_SIZE4:
916 CALL_SQL_GET_DATA(&ptr_value, SQL_C_LONG, sizeof(SQLINTEGER));
917 RETVAL
918 data->d_long = (int) ptr_value.integer;
919 break;
920 case DBI_INTEGER_SIZE8:
921 // SQL_BIGINT is a string!
922 ptr = (SQLPOINTER) malloc(200);
923 CALL_SQL_GET_DATA(ptr, SQL_C_CHAR, 200);
924 RETVAL
925 data->d_longlong = atoll((const char *)ptr);
926 free((SQLPOINTER)ptr);
927 break;
928 default:
929 break;
930 }
931 break;
932 case DBI_TYPE_DECIMAL:
933 switch (result->field_attribs[curfield] & DBI_DECIMAL_SIZEMASK) {
934 case DBI_DECIMAL_SIZE4:
935 CALL_SQL_GET_DATA(&ptr_value, SQL_C_FLOAT, sizeof(SQLREAL));
936 RETVAL
937 data->d_float = (float) ptr_value.real;
938 break;
939 case DBI_DECIMAL_SIZE8:
940 CALL_SQL_GET_DATA(&ptr_value, SQL_C_DOUBLE, sizeof(SQLDOUBLE));
941 RETVAL
942 data->d_double = (double) ptr_value.dbl;
943 break;
944 default:
945 break;
946 }
947 break;
948 case DBI_TYPE_STRING:
949 ptr = (SQLPOINTER) malloc(100);
950 CALL_SQL_GET_DATA(ptr, SQL_C_CHAR, 100);
951 RETVAL
952 data->d_string = strdup((char *)ptr);
953 free((SQLPOINTER)ptr);
954 row->field_sizes[curfield] = 100;
955 break;
956 case DBI_TYPE_BINARY:
957 ptr = (SQLPOINTER) malloc(100);
958 CALL_SQL_GET_DATA(ptr, SQL_C_CHAR, 100);
959 RETVAL
960 data->d_string = strdup((char *)ptr);
961 free((SQLPOINTER)ptr);
962 row->field_sizes[curfield] = 100;
963 break;
964 case DBI_TYPE_DATETIME:
965 ptr_date = malloc(sizeof(char *) * 20);
966 attribs = result->field_attribs[curfield];
967 switch(attribs & (DBI_DATETIME_DATE|DBI_DATETIME_TIME)) {
968 case DBI_DATETIME_DATE:
969 CALL_SQL_GET_DATA(&ptr_value, SQL_C_TYPE_DATE, sizeof(DATE_STRUCT));
970 snprintf(ptr_date, 11, "%d-%d-%d",
971 ptr_value.date.year,
972 ptr_value.date.month,
973 ptr_value.date.day);
974 break;
975 case DBI_DATETIME_TIME:
976 CALL_SQL_GET_DATA(&ptr_value, SQL_C_TYPE_TIME, sizeof(TIME_STRUCT));
977 snprintf(ptr_date, 9, "%.2d:%.2d:%.2d",
978 ptr_value.time.hour,
979 ptr_value.time.minute,
980 ptr_value.time.second);
981 break;
982 case DBI_DATETIME_DATE | DBI_DATETIME_TIME:
983 CALL_SQL_GET_DATA(&ptr_value, SQL_C_TYPE_TIMESTAMP, sizeof(TIMESTAMP_STRUCT));
984 snprintf(ptr_date, 20, "%d-%-d-%d %.2d:%.2d:%.2d",
985 ptr_value.timestamp.year,
986 ptr_value.timestamp.month,
987 ptr_value.timestamp.day,
988 ptr_value.timestamp.hour,
989 ptr_value.timestamp.minute,
990 ptr_value.timestamp.second);
991 break;
992 default:
993 break;
994 }
995 data->d_datetime = _dbd_parse_datetime(ptr_date, attribs);
996 free((char *) ptr_date);
997 break;
998 default:
999 break;
1000 }
1001
1002 curfield++;
1003 }
1004
1005 #undef CALL_SQL_GET_DATA
1006 #undef RETVAL
1007
1008 }
1009
1010 void _set_error_handle(dbi_conn_t *conn, SQLSMALLINT htype, SQLHANDLE hndl)
1011 {
1012
1013 Db2conn *Dconn = conn->connection;
1014
1015 /* We need the handle to get error messages and status code */
1016 Dconn->errorhtype = htype;
1017 Dconn->errorh = (SQLHANDLE *) hndl;
1018
1019 }
1020