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