2
* libdbi - database independent abstraction layer for C.
3
* Copyright (C) 2001-2002, David Parker and Mark Tobenkin.
4
* http://libdbi.sourceforge.net
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
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.
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
20
* dbd_freetds.c: MS SQL database support (using libct of FreeTDS library)
21
* Copyright (C) Vadym Kononenko <konan_v@users.sourceforge.net>.
22
* http://libdbi.sourceforge.net
31
#define _GNU_SOURCE /* we need asprintf */
34
long long atoll(const char *str);
38
long long strtoll(const char *nptr, char **endptr, int base);
48
#include <dbi/dbi-dev.h>
51
#include "dbd_freetds.h"
54
typedef struct freedts_type {
59
static FREETDSCON freetds;
61
static const dbi_info_t driver_info = {
63
"MS SQL and Sybase databases support (using libct)",
64
"Vadym Kononenko <konan_v@users.sourceforge.net>",
65
"http://libdbi.sourceforge.net",
66
"dbd_freetds v" VERSION,
70
static const char APP_NAME[] = "libdbi-freetds-driver";
71
static const char *custom_functions[] = { NULL };
72
static const char *reserved_words[] = TDS_RESERVED_WORDS;
73
static const char freetds_encoding_hash[][16] = {
74
/* Sybase , www.iana.org *//* INTERNAL FREETDS NUMBER */
75
/* Information from internal freetds header 'encodings.h' */
76
"iso_1", "ISO-8859-1", /* 0 */
77
"ascii_8", "ISO-8859-1", /* 0 */
78
"utf8", "UTF-8", /* 1 */
79
"big5", "BIG-5", /* 5 */
80
"cp1250", "CP1250", /* 15 */
81
"cp1251", "CP1251", /* 15 */
82
"cp1252", "CP1252", /* 15 */
83
"cp1253", "CP1253", /* 16 */
84
"cp1254", "CP1254", /* 17 */
85
"cp1255", "CP1255", /* 18 */
86
"cp1256", "CP1256", /* 19 */
87
"cp1257", "CP1257", /* 20 */
88
"cp1258", "CP1258", /* 21 */
89
"cp437", "CP437", /* 23 */
90
"cp850", "CP850", /* 24 */
91
"cp862", "CP862", /* 25 */
92
"cp866", "CP866", /* 26 */
93
"cp874", "CP874", /* 27 */
94
"cp932", "CP932", /* 28 */
95
"cp936", "CP936", /* 29 */
96
"cp949", "CP949", /* 30 */
97
"cp950", "CP950", /* 31 */
98
"iso10", "ISO-8859-10", /* 45 */
99
"iso13", "ISO-8859-13", /* 46 */
100
"iso14", "ISO-8859-14", /* 47 */
101
"iso15", "ISO-8859-15", /* 48 */
102
"iso88592", "ISO-8859-2", /* 50 */
103
"iso88595", "ISO-8859-5", /* 53 */
104
"iso88596", "ISO-8859-6", /* 54 */
105
"iso88597", "ISO-8859-7", /* 55 */
106
"greek8", "ISO-8859-7", /* 55 */
107
"iso88598", "ISO-8859-8", /* 56 */
108
"iso88599", "ISO-8859-9", /* 57 */
109
"tis620", "ISO-IR-166", /* 61 */
110
"koi8", "KOI8-R", /* 65 */
111
"mac", "MAC", /* 69 */
112
"mac_cyr", "MACCYRILLIC", /* 73 */
113
"macgreek", "MACGREEK", /* 74 */
114
"macthai", "MACTHAI", /* 78 */
115
"macturk", "MACTURKISH", /* 79 */
116
"roman8", "ROMAN8", /* 83 */
117
"sjis", "SJIS", /* 84 */
118
"iso646", "US-ASCII", /* 94 */
121
void _dbd_free_row(dbi_result_t * result, dbi_row_t * row);
123
void _translate_freetds_type(CS_DATAFMT * datafmt, unsigned short *type, unsigned int *attribs);
125
size_t _dbd_freetds_escape_chars(char *dest, const char *orig, size_t orig_size,
126
const char *toescape);
128
dbi_row_t *_dbd_freetds_buffers_binding(dbi_conn_t * conn, dbi_result_t * result,
129
CS_DATAFMT ** datafmt, CS_INT * datalength,
130
CS_SMALLINT * ind, CS_RETCODE * ret);
132
void dbd_register_driver(const dbi_info_t ** _driver_info, const char ***_custom_functions,
133
const char ***_reserved_words)
135
/* this is the first function called after the driver module is loaded into memory */
136
*_driver_info = &driver_info;
137
*_custom_functions = custom_functions;
138
*_reserved_words = reserved_words;
141
int dbd_initialize(dbi_driver_t * driver)
143
/* perform any database-specific server initialization.
144
* this is called right after dbd_register_driver().
145
* return -1 on error, 0 on success. if -1 is returned, the driver will not
146
* be added to the list of available drivers. */
150
int dbd_connect(dbi_conn_t * conn)
153
FREETDSCON *tdscon = &freetds;
159
* Allocate memory for structs
161
if (cs_ctx_alloc(CS_VERSION_100, &tdscon->ctx) == CS_SUCCEED) {
162
if (ct_init(tdscon->ctx, CS_VERSION_100) == CS_SUCCEED) {
163
if (ct_con_alloc(tdscon->ctx, &tdscon->conn) == CS_SUCCEED) {
164
if (ct_cmd_alloc(tdscon->conn, &tdscon->cmd) == CS_SUCCEED) {
165
goto success_allocate;
167
/* Deallocate "conn" struct */
168
ct_con_drop(tdscon->conn);
170
/* Go out from client library */
171
ct_exit(tdscon->ctx, CS_UNUSED);
173
/* Deallocate "ctx" struct */
174
cs_ctx_drop(tdscon->ctx);
179
conn->connection = tdscon;
181
/* Set parameters for login */
183
ret = ct_con_props(tdscon->conn, CS_SET, CS_USERNAME,
184
(str = (char *) dbi_conn_get_option(conn, "username")) ? str : "",
186
if (ret != CS_SUCCEED) {
187
// fprintf(stderr, "ct_con_props() SET USERNAME failed!\n");
192
ret = ct_con_props(tdscon->conn, CS_SET, CS_PASSWORD,
193
(str = (char *) dbi_conn_get_option(conn, "password")) ? str : "",
195
if (ret != CS_SUCCEED) {
196
// fprintf(stderr, "ct_con_props() SET PASSWORD failed!\n");
200
/* CHARSET or locale? */
201
/* Describe all locales and charsets in locales.conf file */
202
/* ret = ct_con_props(tdscon->conn, CS_SET, CS_LOC_PROP,
203
(str = (char *) dbi_conn_get_encoding(conn)) ? str : "",
205
if (ret != CS_SUCCEED) {
206
// fprintf(stderr, "ct_con_props() SET LOCALE failed!\n");
210
if ((str = (char *) dbi_conn_get_option(conn, "freetds_version"))) {
211
/* Last VERSION supported by ctlib is 7.0 */
214
// We can use it if "CS_TDS_80" will be add to ct_con_props() by CS_SET action
244
ret = ct_con_props(tdscon->conn, CS_SET, CS_TDS_VERSION, &num, CS_NULLTERM, NULL);
245
if (ret != CS_SUCCEED) {
246
// fprintf(stderr, "ct_con_props() SET VERSION failed!\n");
252
ret = ct_connect(tdscon->conn,
253
(str = (char *) dbi_conn_get_option(conn, "host")) ? str : "", CS_NULLTERM);
254
if (ret != CS_SUCCEED) {
255
// fprintf(stderr, "ct_connect() failed!\n");
262
int dbd_disconnect(dbi_conn_t * conn)
264
FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
266
if (ct_cancel(tdscon->conn, NULL, CS_CANCEL_ALL) != CS_SUCCEED) {
270
ct_cmd_drop(tdscon->cmd);
271
ct_close(tdscon->conn, CS_UNUSED);
272
ct_con_drop(tdscon->conn);
273
ct_exit(tdscon->ctx, CS_UNUSED);
274
cs_ctx_drop(tdscon->ctx);
279
int dbd_fetch_row(dbi_result_t * result, unsigned long long rownum)
281
if (result->result_state == NOTHING_RETURNED)
284
if (result->result_state == ROWS_RETURNED)
285
/* We have already all rows writed to result */
288
/* 0 on error, 1 on successful fetchrow */
291
int dbd_free_query(dbi_result_t * result)
293
/* We don't use any additional memory buffers */
297
int dbd_goto_row(dbi_result_t * result, unsigned long long row)
302
int dbd_get_socket(dbi_conn_t * conn)
304
/* FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
306
if (!(tdscon || tdscon->conn || tdscon->conn->tds_socket))
309
return (int) tdscon->conn->tds_socket->s;
312
* ctlib not allowed to do it and we can't use internal
313
* header ctlib.h for direct acceess to tds structs
318
const char *dbd_get_encoding(dbi_conn_t * conn)
320
FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
321
const char *tds_enc = NULL;
324
/* if (!(tdscon || tdscon->conn || tdscon->conn->tds_login))
327
/* Freetds library use iconv for converting
328
* different charsets between client and server
329
* (if compiled with HAVE_ICONV_ALWAYS and clien_charset is set)
330
* server_charset setted as current clients locale...
332
/* if ((((tds_enc = (const char *) tdscon->conn->tds_login->client_charset)) && strlen(tds_enc)) &&
333
((tds_enc = (const char *) tdscon->conn->tds_login->server_charset)) && strlen(tds_enc))
334
return dbd_encoding_to_iana(tds_enc);
337
/* in ct_con_props(..., CS_VOID* buffer, ...) allocated the mistake */
339
buffer = (CS_VOID *) con->locale;
342
/* I think there should be "*buffer = (CS_VOID *) con->locale;" */
343
ret = ct_con_props(tdscon->conn, CS_GET, CS_LOC_PROP, &tds_enc, CS_NULLTERM, NULL);
344
if (ret != CS_SUCCEED) {
345
// fprintf(stderr, "ct_con_props() SET LOCALE failed!\n");
348
return tds_enc ? dbd_encoding_to_iana(tds_enc) : NULL;
351
const char *dbd_encoding_to_iana(const char *db_encoding)
355
/* loop over all even entries in hash and compare to menc */
356
while (*freetds_encoding_hash[i]) {
357
if (!strncmp(freetds_encoding_hash[i], db_encoding, strlen(freetds_encoding_hash[i]))) {
358
/* return corresponding odd entry */
359
return freetds_encoding_hash[i + 1];
364
/* don't know how to translate, return original encoding */
368
const char *dbd_encoding_from_iana(const char *iana_encoding)
372
/* loop over all odd entries in hash and compare to ienc */
373
while (*freetds_encoding_hash[i + 1]) {
374
if (!strcmp(freetds_encoding_hash[i + 1], iana_encoding)) {
375
/* return corresponding even entry */
376
return freetds_encoding_hash[i];
381
/* don't know how to translate, return original encoding */
382
return iana_encoding;
385
char *dbd_get_engine_version(dbi_conn_t * conn, char *versionstring)
387
dbi_result_t *dbi_result;
388
const char *versioninfo = NULL;
390
/* initialize return string */
391
*versionstring = '\0';
393
dbi_result = dbd_query(conn, "select @@version");
396
if (dbi_result_next_row(dbi_result)) {
400
versioninfo = dbi_result_get_string_idx(dbi_result, 1);
402
/* try to locate the version number. Look for the first dot, go
403
back where the number before the dot starts, then walk
404
forward to the last dot or number */
405
start = strchr(versioninfo, (int) '.');
407
while (--start > versioninfo && isdigit((int) (*start)));
410
while (*stop && (isdigit((int) (*stop)) || *stop == '.')) {
415
/* Last digit not copied to versionstring */
416
if (len && --len < VERSIONSTRING_LENGTH) {
417
strncpy(versionstring, start, len);
418
versionstring[len] = '\0';
422
dbi_result_free(dbi_result);
425
return versionstring;
428
dbi_result_t *dbd_list_dbs(dbi_conn_t * conn, const char *pattern)
433
if (pattern == NULL) {
435
return dbd_query(conn, "exec sp_databases");
437
/* Only this way - nothing another */
439
" create table #t (\n"
440
" DATABASE_NAME sysname NOT NULL,\n"
441
" DATABASE_SIZE int NOT NULL,\n"
442
" REMARKS varchar(254)\n"
444
" Insert Into #t exec sp_databases\n"
445
" Select * From #t Where DATABASE_NAME Like '%%%s%%'\n" " Drop table #t", pattern);
446
res = dbd_query(conn, sql_cmd);
452
dbi_result_t *dbd_list_tables(dbi_conn_t * conn, const char *db, const char *pattern)
457
if (db == NULL || db[0] == '\0') {
458
/* Use current database */
459
res = dbd_query(conn, "EXEC sp_tables");
463
char *current_db = NULL;
464
if (conn->current_db)
465
/* Reserved current DB name */
466
current_db = strdup(conn->current_db);
467
/* MS SQL can show tables only from current DB */
468
dbd_select_db(conn, db);
470
if (pattern == NULL) {
471
asprintf(&sql_cmd, "create table #t (\n"
472
" TABLE_QUALIFIER sysname,\n"
473
" TABLE_OWNER sysname,\n"
474
" TABLE_NAME sysname NOT NULL,\n"
475
" TABLE_TYPE sysname,\n"
476
" REMARKS varchar(254)\n"
478
"Insert Into #t exec sp_tables\n"
479
"Select TABLE_NAME From #t Where TABLE_TYPE='TABLE'\n" "Drop table #t\n");
480
res = dbd_query(conn, sql_cmd);
483
asprintf(&sql_cmd, "create table #t (\n"
484
" TABLE_QUALIFIER sysname,\n"
485
" TABLE_OWNER sysname,\n"
486
" TABLE_NAME sysname NOT NULL,\n"
487
" TABLE_TYPE sysname,\n"
488
" REMARKS varchar(254)\n"
490
"Insert Into #t exec sp_tables\n"
491
"Select TABLE_NAME From #t Where TABLE_TYPE='TABLE' And TABLE_NAME Like '%%%s%%'\n"
492
"Drop table #t\n", pattern);
493
res = dbd_query(conn, sql_cmd);
498
/* Restore previous DB */
499
dbd_select_db(conn, current_db);
507
size_t dbd_quote_string(dbi_driver_t * driver, const char *orig, char *dest)
509
/* foo's -> 'foo''s' */
513
const char *escaped = "\'";
515
len = _dbd_freetds_escape_chars(dest + 1, orig, strlen(orig), escaped);
522
size_t dbd_conn_quote_string(dbi_conn_t * conn, const char *orig, char *dest)
524
return dbd_quote_string(conn->driver, orig, dest);
527
size_t dbd_quote_binary(dbi_conn_t * conn, const unsigned char *orig, size_t from_length,
528
unsigned char **ptr_dest)
533
if ((temp = malloc(from_length * 2)) == NULL) {
537
strcpy((char *) temp, "\'");
539
len = _dbd_encode_binary(orig, from_length, temp + 1);
543
strcat((char *) temp, "'");
551
* Here is a roblem - freetds return only one row and we should step
552
* by step get all rows and save it separately
554
dbi_result_t *dbd_query(dbi_conn_t * conn, const char *statement)
556
/* allocate a new dbi_result_t and fill its applicable members:
558
* result_handle, numrows_matched, and numrows_changed.
559
* everything else will be filled in by DBI */
561
unsigned int idx = 0;
562
dbi_result_t *result = NULL;
563
dbi_row_t *row = NULL;
564
FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
565
CS_RETCODE ret, results_ret;
566
CS_INT result_type, num_cols;
567
CS_DATAFMT **datafmt = NULL;
568
CS_INT datalength = 0;
570
CS_INT count, row_count = 0;
572
ret = ct_command(tdscon->cmd, CS_LANG_CMD, statement, CS_NULLTERM, CS_UNUSED);
573
if (ret != CS_SUCCEED) {
574
// fprintf(stderr, "ct_command() failed\n");
578
ret = ct_send(tdscon->cmd);
579
if (ret != CS_SUCCEED) {
580
// fprintf(stderr, "ct_send() failed\n");
584
while ((results_ret = ct_results(tdscon->cmd, &result_type)) == CS_SUCCEED) {
585
switch ((int) result_type) {
586
case CS_ROWFMT_RESULT:
587
/* here we should allocate memory for received data */
591
if (!((result = _dbd_result_create(conn, NULL, 0 /* Unknown num rows */ ,
592
0 /*numrows_affected */ ))))
595
result->result_state = NOTHING_RETURNED;
605
ret = ct_res_info(tdscon->cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL);
606
if (ret != CS_SUCCEED) {
607
// fprintf(stderr, "ct_res_info() failed");
611
if (!(result = _dbd_result_create(conn, NULL, 0 /* Unknown num rows */ ,
612
0 /*numrows_affected */ )))
615
result->result_state = ROWS_RETURNED;
617
_dbd_result_set_numfields(result, num_cols);
619
/* Fill columns type */
620
for (idx = 0; idx < result->numfields; ++idx) {
621
/* Get information about current column */
622
datafmt = realloc(datafmt, sizeof(CS_DATAFMT *) * (idx + 1));
623
datafmt[idx] = malloc(sizeof(CS_DATAFMT));
625
ret = ct_describe(tdscon->cmd, idx + 1, datafmt[idx]);
626
if (ret != CS_SUCCEED) {
627
// fprintf(stderr, "ct_describe() failed");
631
unsigned short type = 0;
632
unsigned int attribs = 0;
634
_translate_freetds_type(datafmt[idx], &type, &attribs);
635
/* Fill fields value in result */
636
_dbd_result_add_field(result, idx, datafmt[idx]->name, type, attribs);
639
/* Bind all column buffers for current row */
640
if (!(row = _dbd_freetds_buffers_binding(conn, result, datafmt, &datalength,
645
ct_fetch(tdscon->cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED)
646
|| (ret == CS_ROW_FAIL)) {
648
if (ret == CS_ROW_FAIL) {
649
// fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
651
} else if (ret == CS_SUCCEED) {
653
if (!(result->rows = realloc(result->rows, (result->numrows_matched + 2)
654
* sizeof(dbi_row_t *))))
658
_dbd_row_finalize(result, row, result->numrows_matched++);
660
/* Prepare buffer for next row */
661
if (!(row = _dbd_freetds_buffers_binding(conn, result, datafmt, &datalength,
672
/* Last row is reserved - free it */
673
_dbd_free_row(result, row);
675
for (idx = 0; idx < result->numfields; ++idx)
680
// fprintf(stderr, "ct_fetch() returned CS_FAIL.\n");
683
// fprintf(stderr, "ct_fetch() unexpected return.\n");
687
case CS_COMPUTE_RESULT:
688
// fprintf(stderr, "ct_results() unexpected CS_COMPUTE_RESULT.\n");
690
case CS_STATUS_RESULT:
693
// fprintf(stderr, "ct_results() unexpected result_type.\n");
698
switch ((int) results_ret) {
707
// ++(result->numrows_affected);
708
// result->result_handle = tdscon->tds_socket /*->res_info*/ ;
713
dbi_result_t *dbd_query_null(dbi_conn_t * conn, const unsigned char *statement, size_t st_length)
718
const char *dbd_select_db(dbi_conn_t * conn, const char *db)
723
asprintf(&sql_cmd, "USE %s ", db);
724
res = dbd_query(conn, sql_cmd);
731
dbi_result_free(res);
735
int dbd_geterror(dbi_conn_t * conn, int *errno, char **errstr)
737
/* put error number into errno, error string into errstr
738
* return 0 if error, 1 if errno filled, 2 if errstr filled, 3 if both errno and errstr filled */
740
/* We havn't functions for read error types in freetds */
744
unsigned long long dbd_get_seq_last(dbi_conn_t * conn, const char *sequence)
746
// FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
750
len = strlen(sequence);
752
return tds_quote_id(tdscon->tds_socket, NULL, sequence, len) ;
757
unsigned long long dbd_get_seq_next(dbi_conn_t * conn, const char *sequence)
762
int dbd_ping(dbi_conn_t * conn)
766
/* Freetds haven't ping function - use simple query */
767
/* Maybe get another simple query? */
768
res = dbd_query(conn, "SELECT 1") ? 1 : 0;
771
// server is alive and kicking
772
dbd_disconnect(conn);
773
res = dbd_connect(conn);
774
return (res ? 0 : res);
779
void _translate_freetds_type(CS_DATAFMT * datafmt, unsigned short *type, unsigned int *attribs)
781
unsigned int _type = 0;
782
unsigned int _attribs = 0;
783
datafmt->format = CS_FMT_UNUSED;
785
switch (datafmt->datatype /* field type */ ) {
787
case CS_LONG_TYPE: /* 8 */
788
_type = DBI_TYPE_INTEGER;
789
_attribs |= DBI_INTEGER_SIZE8;
791
case CS_INT_TYPE: /* 4 */
792
_type = DBI_TYPE_INTEGER;
793
_attribs |= DBI_INTEGER_SIZE4;
795
case CS_SMALLINT_TYPE: /* 2 */
796
_type = DBI_TYPE_INTEGER;
797
_attribs |= DBI_INTEGER_SIZE2;
799
case CS_BIT_TYPE: /* 1 */
800
case CS_TINYINT_TYPE:
801
_type = DBI_TYPE_INTEGER;
802
_attribs |= DBI_INTEGER_SIZE1;
804
case CS_DATETIME_TYPE: /* 8 */
805
_type = DBI_TYPE_DATETIME;
806
_attribs |= DBI_DATETIME_DATE;
807
_attribs |= DBI_DATETIME_TIME;
809
case CS_DATETIME4_TYPE: /* 4 */
810
_type = DBI_TYPE_DATETIME;
811
_attribs |= DBI_DATETIME_DATE;
812
_attribs |= DBI_DATETIME_TIME;
814
case CS_REAL_TYPE: /* 4 */
815
_type = DBI_TYPE_DECIMAL;
816
_attribs |= DBI_DECIMAL_SIZE4;
818
case CS_FLOAT_TYPE: /* 8 */
819
_type = DBI_TYPE_DECIMAL;
820
_attribs |= DBI_DECIMAL_SIZE8;
824
case CS_VARCHAR_TYPE:
825
_type = DBI_TYPE_STRING;
826
datafmt->format = CS_FMT_NULLTERM;
828
case CS_MONEY_TYPE: /* 8 */
829
case CS_MONEY4_TYPE: /* 4 */
830
case CS_NUMERIC_TYPE:
831
case CS_DECIMAL_TYPE:
835
case CS_VARBINARY_TYPE:
836
case CS_UNICHAR_TYPE:
839
_type = DBI_TYPE_BINARY;
846
size_t _dbd_freetds_escape_chars(char *dest, const char *orig, size_t orig_size,
847
const char *toescape)
849
char *curdest = dest;
850
const char *curorig = orig;
851
const char *curescaped;
854
while (curorig && curorig < orig + orig_size) {
855
curescaped = toescape;
856
while (curescaped && *curescaped) {
857
if (*curorig == *curescaped) {
864
/* Copy char to destination */
872
/* append a NULL byte. This is required if orig was a
873
zero-terminated string. It does not hurt if orig was a
874
binary string as the calling function is not supposed to
875
read past len bytes */
880
dbi_row_t *_dbd_freetds_buffers_binding(dbi_conn_t * conn, dbi_result_t * result,
881
CS_DATAFMT ** datafmt, CS_INT * datalength,
882
CS_SMALLINT * ind, CS_RETCODE * ret)
884
dbi_row_t *row = NULL;
885
unsigned int idx = 0;
888
FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
890
/* Allocate memory for current row */
891
if (!(row = _dbd_row_allocate(result->numfields)))
894
for (idx = 0; idx < result->numfields; ++idx) {
895
/* Processing data from previous row */
896
if (result->numrows_matched > 0) {
898
* We should convert data from previous row
899
* to libdbi datatypes. We converted types here
900
* because we should know CS_ data types.
902
switch (datafmt[idx]->datatype) {
903
case CS_MONEY_TYPE: /* 8 */
904
case CS_MONEY4_TYPE: /* 4 */
908
dstfmt.datatype = CS_NUMERIC_TYPE;
909
dstfmt.maxlength = sizeof(CS_NUMERIC_TYPE);
910
dstfmt.locale = NULL;
911
dstfmt.format = CS_FMT_UNUSED;
913
addr = malloc(sizeof(CS_NUMERIC_TYPE));
915
&(result->rows[result->numrows_matched]->field_values[idx].d_string);
917
if (cs_convert(tdscon->ctx, datafmt[idx], *orig, &dstfmt, addr, NULL) !=
919
// fprintf(stderr, "cs_convert() succeeded when failure was expected\n");
925
case CS_DATETIME_TYPE: /* 8 */
926
case CS_DATETIME4_TYPE: /* 4 */
931
dstfmt.datatype = CS_TEXT_TYPE;
932
dstfmt.maxlength = 20;
933
dstfmt.locale = NULL;
934
dstfmt.format = CS_FMT_NULLTERM;
936
addr = &(result->rows[result->numrows_matched]->field_values[idx]);
938
if (cs_convert(tdscon->ctx, datafmt[idx], addr, &dstfmt, datastring, NULL) !=
940
// fprintf(stderr, "cs_convert() succeeded when failure was expected\n");
942
((dbi_data_t *) addr)->d_datetime =
943
_dbd_parse_datetime(datastring, DBI_DATETIME_TIME | DBI_DATETIME_DATE);
946
/* decode binary string */
950
case CS_VARBINARY_TYPE:
951
case CS_UNICHAR_TYPE:
953
addr = result->rows[result->numrows_matched];
956
((dbi_row_t *) addr)->field_sizes[idx] =
957
_dbd_decode_binary(((dbi_row_t *) addr)->field_values[idx].d_string,
958
((dbi_row_t *) addr)->field_values[idx].d_string);
962
case CS_VARCHAR_TYPE:
963
addr = result->rows[result->numrows_matched];
965
((dbi_row_t *) addr)->field_sizes[idx] =
966
strlen(((dbi_row_t *) addr)->field_values[idx].d_string);
971
/* Bind all columns buffer for current row */
972
row->field_sizes[idx] = datafmt[idx]->maxlength;
974
switch (result->field_types[idx]) {
975
case DBI_TYPE_BINARY:
976
case DBI_TYPE_STRING:
978
* Result is more that 8 bytes -
979
* allocate additional memory
981
addr = row->field_values[idx].d_string = (char *) malloc(row->field_sizes[idx]);
984
/* Prepare union to data copy */
985
bzero((addr = &row->field_values[idx]), sizeof(dbi_data_t));
987
*ret = ct_bind(tdscon->cmd, idx + 1, datafmt[idx], addr, datalength, ind);
988
if (*ret != CS_SUCCEED) {
989
// fprintf(stderr, "ct_bind() failed\n");
993
/* All columns buffer binded */
997
void _dbd_free_row(dbi_result_t * result, dbi_row_t * row)
999
unsigned int idx = 0;
1001
for (idx = 0; idx < result->numfields; ++idx) {
1002
if (result->field_types[idx] == DBI_TYPE_BINARY ||
1003
result->field_types[idx] == DBI_TYPE_STRING) {
1004
free(row->field_values[idx].d_string);
1007
free(row->field_values);
1008
free(row->field_sizes);
1009
free(row->field_flags);