~ubuntu-branches/ubuntu/precise/libdbi-drivers/precise

« back to all changes in this revision

Viewing changes to drivers/freetds/dbd_freetds.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2008-08-02 09:00:11 UTC
  • mfrom: (3.1.6 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080802090011-j05v2349u2ptvg05
Tags: 0.8.2-1-4.1
* Non-maintainer upload with maintainer's approval.
* High urgency upload for RC bugfix.
* Pass --freetds-inc-dir to configure, to bypass the ridiculous upstream
  AC_FIND_FILE() checks for files that *aren't used during the build*;
  fixes a build failure with FreeTDS 0.82.  Closes: #493349.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
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_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
 
23
 * 
 
24
 * 
 
25
 */
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#include <config.h>
 
29
#endif
 
30
 
 
31
#define _GNU_SOURCE             /* we need asprintf */
 
32
 
 
33
#ifndef HAVE_ATOLL
 
34
long long atoll(const char *str);
 
35
#endif
 
36
 
 
37
#ifndef HAVE_STRTOLL
 
38
long long strtoll(const char *nptr, char **endptr, int base);
 
39
#endif
 
40
 
 
41
#include <stdio.h>
 
42
#include <stdlib.h>
 
43
#include <string.h>
 
44
#include <ctype.h>
 
45
#include <time.h>
 
46
 
 
47
#include <dbi/dbi.h>
 
48
#include <dbi/dbi-dev.h>
 
49
#include <dbi/dbd.h>
 
50
 
 
51
#include "dbd_freetds.h"
 
52
#include <ctpublic.h>
 
53
 
 
54
typedef struct freedts_type {
 
55
    CS_CONTEXT *ctx;
 
56
    CS_CONNECTION *conn;
 
57
    CS_COMMAND *cmd;
 
58
} FREETDSCON;
 
59
static FREETDSCON freetds;
 
60
 
 
61
static const dbi_info_t driver_info = {
 
62
    "freetds",
 
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,
 
67
    __DATE__
 
68
};
 
69
 
 
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 */
 
119
    "", ""
 
120
};
 
121
void _dbd_free_row(dbi_result_t * result, dbi_row_t * row);
 
122
 
 
123
void _translate_freetds_type(CS_DATAFMT * datafmt, unsigned short *type, unsigned int *attribs);
 
124
 
 
125
size_t _dbd_freetds_escape_chars(char *dest, const char *orig, size_t orig_size,
 
126
                                 const char *toescape);
 
127
 
 
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);
 
131
 
 
132
void dbd_register_driver(const dbi_info_t ** _driver_info, const char ***_custom_functions,
 
133
                         const char ***_reserved_words)
 
134
{
 
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;
 
139
}
 
140
 
 
141
int dbd_initialize(dbi_driver_t * driver)
 
142
{
 
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. */
 
147
    return 0;
 
148
}
 
149
 
 
150
int dbd_connect(dbi_conn_t * conn)
 
151
{
 
152
 
 
153
    FREETDSCON *tdscon = &freetds;
 
154
    CS_RETCODE ret;
 
155
 
 
156
    char *str;
 
157
    unsigned int num;
 
158
/*
 
159
 * Allocate memory for structs
 
160
 */
 
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;
 
166
                }
 
167
                /* Deallocate "conn" struct */
 
168
                ct_con_drop(tdscon->conn);
 
169
            }
 
170
            /* Go out from client library */
 
171
            ct_exit(tdscon->ctx, CS_UNUSED);
 
172
        }
 
173
        /* Deallocate "ctx" struct */
 
174
        cs_ctx_drop(tdscon->ctx);
 
175
    }
 
176
 
 
177
    return -1;
 
178
  success_allocate:
 
179
    conn->connection = tdscon;
 
180
 
 
181
    /* Set parameters for login */
 
182
    /* USERNAME */
 
183
    ret = ct_con_props(tdscon->conn, CS_SET, CS_USERNAME,
 
184
                       (str = (char *) dbi_conn_get_option(conn, "username")) ? str : "",
 
185
                       CS_NULLTERM, NULL);
 
186
    if (ret != CS_SUCCEED) {
 
187
        // fprintf(stderr, "ct_con_props() SET USERNAME failed!\n");
 
188
        return -1;
 
189
    }
 
190
 
 
191
    /* PASSWORD */
 
192
    ret = ct_con_props(tdscon->conn, CS_SET, CS_PASSWORD,
 
193
                       (str = (char *) dbi_conn_get_option(conn, "password")) ? str : "",
 
194
                       CS_NULLTERM, NULL);
 
195
    if (ret != CS_SUCCEED) {
 
196
        // fprintf(stderr, "ct_con_props() SET PASSWORD failed!\n");
 
197
        return -1;
 
198
    }
 
199
 
 
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 : "",
 
204
                       CS_NULLTERM, NULL);
 
205
    if (ret != CS_SUCCEED) {
 
206
        // fprintf(stderr, "ct_con_props() SET LOCALE failed!\n");
 
207
        return -1;
 
208
    }
 
209
*/
 
210
    if ((str = (char *) dbi_conn_get_option(conn, "freetds_version"))) {
 
211
        /* Last VERSION supported by ctlib is 7.0 */
 
212
        // Format = X.XX.XX
 
213
        switch (str[0]) {
 
214
//      We can use it if "CS_TDS_80" will be add to ct_con_props() by CS_SET action
 
215
        case '8':
 
216
            num = CS_TDS_80;
 
217
            break;
 
218
        case '7':
 
219
            num = CS_TDS_70;
 
220
            break;
 
221
        case '5':
 
222
            num = CS_TDS_50;
 
223
            break;
 
224
        case '4':
 
225
            {
 
226
                switch (str[2]) {
 
227
                case '6':
 
228
                    num = CS_TDS_46;
 
229
                    break;
 
230
                case '9':
 
231
                    num = CS_TDS_495;
 
232
                    break;
 
233
                case '0':
 
234
                case '2':
 
235
                default:
 
236
                    num = CS_TDS_40;
 
237
                }
 
238
            }
 
239
            break;
 
240
        default:
 
241
            num = CS_TDS_40;
 
242
        }
 
243
 
 
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");
 
247
            return -1;
 
248
        }
 
249
    }
 
250
 
 
251
    /* Connect to CLI */
 
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");
 
256
        return -1;
 
257
    }
 
258
 
 
259
    return 0;
 
260
}
 
261
 
 
262
int dbd_disconnect(dbi_conn_t * conn)
 
263
{
 
264
    FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
 
265
 
 
266
    if (ct_cancel(tdscon->conn, NULL, CS_CANCEL_ALL) != CS_SUCCEED) {
 
267
        return 1;
 
268
    }
 
269
 
 
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);
 
275
 
 
276
    return 0;
 
277
}
 
278
 
 
279
int dbd_fetch_row(dbi_result_t * result, unsigned long long rownum)
 
280
{
 
281
    if (result->result_state == NOTHING_RETURNED)
 
282
        return -1;
 
283
 
 
284
    if (result->result_state == ROWS_RETURNED)
 
285
        /* We have already all rows writed to result */
 
286
        return 1;
 
287
    return 0;
 
288
    /* 0 on error, 1 on successful fetchrow */
 
289
}
 
290
 
 
291
int dbd_free_query(dbi_result_t * result)
 
292
{
 
293
    /* We don't use any additional memory buffers */
 
294
    return 0;
 
295
}
 
296
 
 
297
int dbd_goto_row(dbi_result_t * result, unsigned long long row)
 
298
{
 
299
    return 1;
 
300
}
 
301
 
 
302
int dbd_get_socket(dbi_conn_t * conn)
 
303
{
 
304
/*    FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
 
305
 
 
306
    if (!(tdscon || tdscon->conn || tdscon->conn->tds_socket))
 
307
        return -1;
 
308
 
 
309
    return (int) tdscon->conn->tds_socket->s;
 
310
*/
 
311
/* 
 
312
 * ctlib not allowed to do it and we can't use internal 
 
313
 * header ctlib.h for direct acceess to tds structs
 
314
 */
 
315
    return 0;
 
316
}
 
317
 
 
318
const char *dbd_get_encoding(dbi_conn_t * conn)
 
319
{
 
320
    FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
 
321
    const char *tds_enc = NULL;
 
322
    CS_RETCODE ret;
 
323
 
 
324
/*    if (!(tdscon || tdscon->conn || tdscon->conn->tds_login))
 
325
        return NULL;
 
326
*/
 
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...
 
331
     */
 
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);
 
335
*/
 
336
 
 
337
/* in ct_con_props(..., CS_VOID* buffer, ...) allocated the mistake */
 
338
/*                case CS_LOC_PROP:
 
339
                        buffer = (CS_VOID *) con->locale;
 
340
                    break;
 
341
*/
 
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");
 
346
        return NULL;
 
347
    }
 
348
    return tds_enc ? dbd_encoding_to_iana(tds_enc) : NULL;
 
349
}
 
350
 
 
351
const char *dbd_encoding_to_iana(const char *db_encoding)
 
352
{
 
353
    int i = 0;
 
354
 
 
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];
 
360
        }
 
361
        i += 2;
 
362
    }
 
363
 
 
364
    /* don't know how to translate, return original encoding */
 
365
    return db_encoding;
 
366
}
 
367
 
 
368
const char *dbd_encoding_from_iana(const char *iana_encoding)
 
369
{
 
370
    int i = 0;
 
371
 
 
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];
 
377
        }
 
378
        i += 2;
 
379
    }
 
380
 
 
381
    /* don't know how to translate, return original encoding */
 
382
    return iana_encoding;
 
383
}
 
384
 
 
385
char *dbd_get_engine_version(dbi_conn_t * conn, char *versionstring)
 
386
{
 
387
    dbi_result_t *dbi_result;
 
388
    const char *versioninfo = NULL;
 
389
 
 
390
    /* initialize return string */
 
391
    *versionstring = '\0';
 
392
 
 
393
    dbi_result = dbd_query(conn, "select @@version");
 
394
 
 
395
    if (dbi_result) {
 
396
        if (dbi_result_next_row(dbi_result)) {
 
397
            char *start = NULL;
 
398
            char *stop = NULL;
 
399
            int len = 0;
 
400
            versioninfo = dbi_result_get_string_idx(dbi_result, 1);
 
401
 
 
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) '.');
 
406
            if (start) {
 
407
                while (--start > versioninfo && isdigit((int) (*start)));
 
408
 
 
409
                stop = ++start;
 
410
                while (*stop && (isdigit((int) (*stop)) || *stop == '.')) {
 
411
                    stop++;
 
412
                }
 
413
 
 
414
                len = stop - start;
 
415
                /* Last digit not copied to versionstring */
 
416
                if (len && --len < VERSIONSTRING_LENGTH) {
 
417
                    strncpy(versionstring, start, len);
 
418
                    versionstring[len] = '\0';
 
419
                }
 
420
            }
 
421
        }
 
422
        dbi_result_free(dbi_result);
 
423
    }
 
424
 
 
425
    return versionstring;
 
426
}
 
427
 
 
428
dbi_result_t *dbd_list_dbs(dbi_conn_t * conn, const char *pattern)
 
429
{
 
430
    dbi_result_t *res;
 
431
    char *sql_cmd;
 
432
 
 
433
    if (pattern == NULL) {
 
434
 
 
435
        return dbd_query(conn, "exec sp_databases");
 
436
    } else {
 
437
        /* Only this way - nothing another */
 
438
        asprintf(&sql_cmd,
 
439
                 " create table #t (\n"
 
440
                 "                  DATABASE_NAME sysname NOT NULL,\n"
 
441
                 "                  DATABASE_SIZE int NOT NULL,\n"
 
442
                 "                  REMARKS varchar(254)\n"
 
443
                 "                )\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);
 
447
        free(sql_cmd);
 
448
        return res;
 
449
    }
 
450
}
 
451
 
 
452
dbi_result_t *dbd_list_tables(dbi_conn_t * conn, const char *db, const char *pattern)
 
453
{
 
454
    dbi_result_t *res;
 
455
    char *sql_cmd;
 
456
 
 
457
    if (db == NULL || db[0] == '\0') {
 
458
        /* Use current database */
 
459
        res = dbd_query(conn, "EXEC sp_tables");
 
460
        return res;
 
461
    }
 
462
 
 
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);
 
469
 
 
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"
 
477
                 "                 )\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);
 
481
        free(sql_cmd);
 
482
    } else {
 
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"
 
489
                 "                 )\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);
 
494
        free(sql_cmd);
 
495
    }
 
496
 
 
497
    if (current_db) {
 
498
        /* Restore previous DB */
 
499
        dbd_select_db(conn, current_db);
 
500
        free(current_db);
 
501
    }
 
502
    return res;
 
503
}
 
504
 
 
505
 
 
506
 
 
507
size_t dbd_quote_string(dbi_driver_t * driver, const char *orig, char *dest)
 
508
{
 
509
    /* foo's -> 'foo''s' */
 
510
    size_t len;
 
511
 
 
512
    strcpy(dest, "\'");
 
513
    const char *escaped = "\'";
 
514
 
 
515
    len = _dbd_freetds_escape_chars(dest + 1, orig, strlen(orig), escaped);
 
516
 
 
517
    strcat(dest, "'");
 
518
 
 
519
    return len + 2;
 
520
}
 
521
 
 
522
size_t dbd_conn_quote_string(dbi_conn_t * conn, const char *orig, char *dest)
 
523
{
 
524
    return dbd_quote_string(conn->driver, orig, dest);
 
525
}
 
526
 
 
527
size_t dbd_quote_binary(dbi_conn_t * conn, const unsigned char *orig, size_t from_length,
 
528
                        unsigned char **ptr_dest)
 
529
{
 
530
    unsigned char *temp;
 
531
    size_t len;
 
532
 
 
533
    if ((temp = malloc(from_length * 2)) == NULL) {
 
534
        return 0;
 
535
    }
 
536
 
 
537
    strcpy((char *) temp, "\'");
 
538
    if (from_length) {
 
539
        len = _dbd_encode_binary(orig, from_length, temp + 1);
 
540
    } else {
 
541
        len = 0;
 
542
    }
 
543
    strcat((char *) temp, "'");
 
544
 
 
545
    *ptr_dest = temp;
 
546
 
 
547
    return len + 2;
 
548
}
 
549
 
 
550
/* 
 
551
 * Here is a roblem - freetds return only one row and we should step
 
552
 * by step get all rows and save it separately
 
553
 */
 
554
dbi_result_t *dbd_query(dbi_conn_t * conn, const char *statement)
 
555
{
 
556
    /* allocate a new dbi_result_t and fill its applicable members:
 
557
     * 
 
558
     * result_handle, numrows_matched, and numrows_changed.
 
559
     * everything else will be filled in by DBI */
 
560
 
 
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;
 
569
    CS_SMALLINT ind = 0;
 
570
    CS_INT count, row_count = 0;
 
571
 
 
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");
 
575
        return NULL;
 
576
    }
 
577
 
 
578
    ret = ct_send(tdscon->cmd);
 
579
    if (ret != CS_SUCCEED) {
 
580
        // fprintf(stderr, "ct_send() failed\n");
 
581
        return NULL;
 
582
    }
 
583
 
 
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 */
 
588
            break;
 
589
        case CS_CMD_SUCCEED:
 
590
            if (!result) {
 
591
                if (!((result = _dbd_result_create(conn, NULL, 0 /* Unknown num rows */ ,
 
592
                                                   0 /*numrows_affected */ ))))
 
593
                    /* Out of memory */
 
594
                    return NULL;
 
595
                result->result_state = NOTHING_RETURNED;
 
596
            }
 
597
            break;
 
598
        case CS_CMD_DONE:
 
599
            break;
 
600
        case CS_CMD_FAIL:
 
601
            /* ? */
 
602
            return NULL;
 
603
            break;
 
604
        case CS_ROW_RESULT:
 
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");
 
608
                return NULL;
 
609
            }
 
610
 
 
611
            if (!(result = _dbd_result_create(conn, NULL, 0 /* Unknown num rows */ ,
 
612
                                              0 /*numrows_affected */ )))
 
613
                /* Out of memory */
 
614
                return NULL;
 
615
            result->result_state = ROWS_RETURNED;
 
616
 
 
617
            _dbd_result_set_numfields(result, num_cols);
 
618
 
 
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));
 
624
 
 
625
                ret = ct_describe(tdscon->cmd, idx + 1, datafmt[idx]);
 
626
                if (ret != CS_SUCCEED) {
 
627
                    // fprintf(stderr, "ct_describe() failed");
 
628
                    return NULL;
 
629
                }
 
630
 
 
631
                unsigned short type = 0;
 
632
                unsigned int attribs = 0;
 
633
 
 
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);
 
637
            }
 
638
 
 
639
            /* Bind all column buffers for current row */
 
640
            if (!(row = _dbd_freetds_buffers_binding(conn, result, datafmt, &datalength,
 
641
                                                     &ind, &ret)))
 
642
                return NULL;
 
643
 
 
644
            while (((ret =
 
645
                     ct_fetch(tdscon->cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED)
 
646
                   || (ret == CS_ROW_FAIL)) {
 
647
                row_count += count;
 
648
                if (ret == CS_ROW_FAIL) {
 
649
                    // fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
 
650
                    return NULL;
 
651
                } else if (ret == CS_SUCCEED) {
 
652
                    /* Save row */
 
653
                    if (!(result->rows = realloc(result->rows, (result->numrows_matched + 2)
 
654
                                                 * sizeof(dbi_row_t *))))
 
655
                        /* Out of memory */
 
656
                        return NULL;
 
657
 
 
658
                    _dbd_row_finalize(result, row, result->numrows_matched++);
 
659
 
 
660
                    /* Prepare buffer for next row */
 
661
                    if (!(row = _dbd_freetds_buffers_binding(conn, result, datafmt, &datalength,
 
662
                                                             &ind, &ret)))
 
663
                        return NULL;
 
664
 
 
665
                } else {
 
666
                    break;
 
667
                }
 
668
            }
 
669
            /* Last return */
 
670
            switch ((int) ret) {
 
671
            case CS_END_DATA:
 
672
                /* Last row is reserved - free it */
 
673
                _dbd_free_row(result, row);
 
674
 
 
675
                for (idx = 0; idx < result->numfields; ++idx)
 
676
                    free(datafmt[idx]);
 
677
                free(datafmt);
 
678
                break;
 
679
            case CS_FAIL:
 
680
                // fprintf(stderr, "ct_fetch() returned CS_FAIL.\n");
 
681
                return NULL;
 
682
            default:
 
683
                // fprintf(stderr, "ct_fetch() unexpected return.\n");
 
684
                return NULL;
 
685
            }
 
686
            break;
 
687
        case CS_COMPUTE_RESULT:
 
688
            // fprintf(stderr, "ct_results() unexpected CS_COMPUTE_RESULT.\n");
 
689
            return NULL;
 
690
        case CS_STATUS_RESULT:
 
691
            break;
 
692
        default:
 
693
            // fprintf(stderr, "ct_results() unexpected result_type.\n");
 
694
            return NULL;
 
695
        }
 
696
    }
 
697
 
 
698
    switch ((int) results_ret) {
 
699
    case CS_END_RESULTS:
 
700
        break;
 
701
    case CS_FAIL:
 
702
        return NULL;
 
703
        break;
 
704
    default:
 
705
        return NULL;
 
706
    }
 
707
//    ++(result->numrows_affected);
 
708
//    result->result_handle = tdscon->tds_socket /*->res_info*/ ;
 
709
 
 
710
    return result;
 
711
}
 
712
 
 
713
dbi_result_t *dbd_query_null(dbi_conn_t * conn, const unsigned char *statement, size_t st_length)
 
714
{
 
715
    return NULL;
 
716
}
 
717
 
 
718
const char *dbd_select_db(dbi_conn_t * conn, const char *db)
 
719
{
 
720
    dbi_result_t *res;
 
721
    char *sql_cmd;
 
722
 
 
723
    asprintf(&sql_cmd, "USE %s ", db);
 
724
    res = dbd_query(conn, sql_cmd);
 
725
    free(sql_cmd);
 
726
 
 
727
    if (!res) {
 
728
        return NULL;
 
729
    }
 
730
 
 
731
    dbi_result_free(res);
 
732
    return (char *) db;
 
733
}
 
734
 
 
735
int dbd_geterror(dbi_conn_t * conn, int *errno, char **errstr)
 
736
{
 
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 */
 
739
 
 
740
    /* We havn't functions for read error types in freetds */
 
741
    return -1;
 
742
}
 
743
 
 
744
unsigned long long dbd_get_seq_last(dbi_conn_t * conn, const char *sequence)
 
745
{
 
746
//    FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
 
747
/*    int len = 0;
 
748
 
 
749
    if (sequence)
 
750
        len = strlen(sequence);
 
751
 
 
752
    return tds_quote_id(tdscon->tds_socket, NULL, sequence, len) ;
 
753
*/
 
754
    return 0;
 
755
}
 
756
 
 
757
unsigned long long dbd_get_seq_next(dbi_conn_t * conn, const char *sequence)
 
758
{
 
759
    return 0;
 
760
}
 
761
 
 
762
int dbd_ping(dbi_conn_t * conn)
 
763
{
 
764
 
 
765
    int res;
 
766
    /* Freetds haven't ping function - use simple query */
 
767
    /* Maybe get another simple query? */
 
768
    res = dbd_query(conn, "SELECT 1") ? 1 : 0;
 
769
 
 
770
    if (!res) {
 
771
        // server is alive and kicking
 
772
        dbd_disconnect(conn);
 
773
        res = dbd_connect(conn);
 
774
        return (res ? 0 : res);
 
775
    }
 
776
    return res;
 
777
}
 
778
 
 
779
void _translate_freetds_type(CS_DATAFMT * datafmt, unsigned short *type, unsigned int *attribs)
 
780
{
 
781
    unsigned int _type = 0;
 
782
    unsigned int _attribs = 0;
 
783
    datafmt->format = CS_FMT_UNUSED;
 
784
 
 
785
    switch (datafmt->datatype /* field type */ ) {
 
786
 
 
787
    case CS_LONG_TYPE:          /* 8 */
 
788
        _type = DBI_TYPE_INTEGER;
 
789
        _attribs |= DBI_INTEGER_SIZE8;
 
790
        break;
 
791
    case CS_INT_TYPE:           /* 4 */
 
792
        _type = DBI_TYPE_INTEGER;
 
793
        _attribs |= DBI_INTEGER_SIZE4;
 
794
        break;
 
795
    case CS_SMALLINT_TYPE:      /* 2 */
 
796
        _type = DBI_TYPE_INTEGER;
 
797
        _attribs |= DBI_INTEGER_SIZE2;
 
798
        break;
 
799
    case CS_BIT_TYPE:           /* 1 */
 
800
    case CS_TINYINT_TYPE:
 
801
        _type = DBI_TYPE_INTEGER;
 
802
        _attribs |= DBI_INTEGER_SIZE1;
 
803
        break;
 
804
    case CS_DATETIME_TYPE:      /* 8 */
 
805
        _type = DBI_TYPE_DATETIME;
 
806
        _attribs |= DBI_DATETIME_DATE;
 
807
        _attribs |= DBI_DATETIME_TIME;
 
808
        break;
 
809
    case CS_DATETIME4_TYPE:     /* 4 */
 
810
        _type = DBI_TYPE_DATETIME;
 
811
        _attribs |= DBI_DATETIME_DATE;
 
812
        _attribs |= DBI_DATETIME_TIME;
 
813
        break;
 
814
    case CS_REAL_TYPE:          /* 4 */
 
815
        _type = DBI_TYPE_DECIMAL;
 
816
        _attribs |= DBI_DECIMAL_SIZE4;
 
817
        break;
 
818
    case CS_FLOAT_TYPE: /* 8 */
 
819
        _type = DBI_TYPE_DECIMAL;
 
820
        _attribs |= DBI_DECIMAL_SIZE8;
 
821
        break;
 
822
    case CS_CHAR_TYPE:
 
823
    case CS_TEXT_TYPE:
 
824
    case CS_VARCHAR_TYPE:
 
825
        _type = DBI_TYPE_STRING;
 
826
        datafmt->format = CS_FMT_NULLTERM;
 
827
        break;
 
828
    case CS_MONEY_TYPE: /* 8 */
 
829
    case CS_MONEY4_TYPE:        /* 4 */
 
830
    case CS_NUMERIC_TYPE:
 
831
    case CS_DECIMAL_TYPE:
 
832
    case CS_UNIQUE_TYPE:
 
833
    case CS_IMAGE_TYPE:
 
834
    case CS_BINARY_TYPE:
 
835
    case CS_VARBINARY_TYPE:
 
836
    case CS_UNICHAR_TYPE:
 
837
 
 
838
    default:
 
839
        _type = DBI_TYPE_BINARY;
 
840
    }
 
841
 
 
842
    *type = _type;
 
843
    *attribs = _attribs;
 
844
}
 
845
 
 
846
size_t _dbd_freetds_escape_chars(char *dest, const char *orig, size_t orig_size,
 
847
                                 const char *toescape)
 
848
{
 
849
    char *curdest = dest;
 
850
    const char *curorig = orig;
 
851
    const char *curescaped;
 
852
    size_t len = 0;
 
853
 
 
854
    while (curorig && curorig < orig + orig_size) {
 
855
        curescaped = toescape;
 
856
        while (curescaped && *curescaped) {
 
857
            if (*curorig == *curescaped) {
 
858
                *(curdest++) = '\'';
 
859
                len++;
 
860
                break;
 
861
            }
 
862
            curescaped++;
 
863
        }
 
864
        /* Copy char to destination */
 
865
        *curdest = *curorig;
 
866
 
 
867
        curorig++;
 
868
        curdest++;
 
869
        len++;
 
870
    }
 
871
 
 
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 */
 
876
    *curdest = '\0';
 
877
    return len;
 
878
}
 
879
 
 
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)
 
883
{
 
884
    dbi_row_t *row = NULL;
 
885
    unsigned int idx = 0;
 
886
    void *addr = NULL;
 
887
 
 
888
    FREETDSCON *tdscon = (FREETDSCON *) conn->connection;
 
889
 
 
890
    /* Allocate memory for current row */
 
891
    if (!(row = _dbd_row_allocate(result->numfields)))
 
892
        /* Out of memory */
 
893
        return NULL;
 
894
    for (idx = 0; idx < result->numfields; ++idx) {
 
895
        /* Processing data from previous row */
 
896
        if (result->numrows_matched > 0) {
 
897
            /* 
 
898
             * We should convert data from previous row 
 
899
             * to libdbi datatypes. We converted types here 
 
900
             * because we should know CS_ data types.
 
901
             */
 
902
            switch (datafmt[idx]->datatype) {
 
903
            case CS_MONEY_TYPE: /* 8 */
 
904
            case CS_MONEY4_TYPE:        /* 4 */
 
905
                {
 
906
                    CS_DATAFMT dstfmt;
 
907
 
 
908
                    dstfmt.datatype = CS_NUMERIC_TYPE;
 
909
                    dstfmt.maxlength = sizeof(CS_NUMERIC_TYPE);
 
910
                    dstfmt.locale = NULL;
 
911
                    dstfmt.format = CS_FMT_UNUSED;
 
912
 
 
913
                    addr = malloc(sizeof(CS_NUMERIC_TYPE));
 
914
                    char **orig =
 
915
                        &(result->rows[result->numrows_matched]->field_values[idx].d_string);
 
916
 
 
917
                    if (cs_convert(tdscon->ctx, datafmt[idx], *orig, &dstfmt, addr, NULL) !=
 
918
                        CS_SUCCEED) {
 
919
                        // fprintf(stderr, "cs_convert() succeeded when failure was expected\n");
 
920
                    }
 
921
                    free(*orig);
 
922
                    *orig = addr;
 
923
                }
 
924
                break;
 
925
            case CS_DATETIME_TYPE:      /* 8 */
 
926
            case CS_DATETIME4_TYPE:     /* 4 */
 
927
                {
 
928
                    char datastring[20];
 
929
                    CS_DATAFMT dstfmt;
 
930
 
 
931
                    dstfmt.datatype = CS_TEXT_TYPE;
 
932
                    dstfmt.maxlength = 20;
 
933
                    dstfmt.locale = NULL;
 
934
                    dstfmt.format = CS_FMT_NULLTERM;
 
935
 
 
936
                    addr = &(result->rows[result->numrows_matched]->field_values[idx]);
 
937
 
 
938
                    if (cs_convert(tdscon->ctx, datafmt[idx], addr, &dstfmt, datastring, NULL) !=
 
939
                        CS_SUCCEED) {
 
940
                        // fprintf(stderr, "cs_convert() succeeded when failure was expected\n");
 
941
                    }
 
942
                    ((dbi_data_t *) addr)->d_datetime =
 
943
                        _dbd_parse_datetime(datastring, DBI_DATETIME_TIME | DBI_DATETIME_DATE);
 
944
                }
 
945
                break;
 
946
                /* decode binary string */
 
947
            case CS_UNIQUE_TYPE:
 
948
            case CS_IMAGE_TYPE:
 
949
            case CS_BINARY_TYPE:
 
950
            case CS_VARBINARY_TYPE:
 
951
            case CS_UNICHAR_TYPE:
 
952
 
 
953
                addr = result->rows[result->numrows_matched];
 
954
 
 
955
 
 
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);
 
959
                break;
 
960
            case CS_CHAR_TYPE:
 
961
            case CS_TEXT_TYPE:
 
962
            case CS_VARCHAR_TYPE:
 
963
                addr = result->rows[result->numrows_matched];
 
964
 
 
965
                ((dbi_row_t *) addr)->field_sizes[idx] =
 
966
                    strlen(((dbi_row_t *) addr)->field_values[idx].d_string);
 
967
                break;
 
968
            }
 
969
        }
 
970
 
 
971
        /* Bind all columns buffer for current row */
 
972
        row->field_sizes[idx] = datafmt[idx]->maxlength;
 
973
 
 
974
        switch (result->field_types[idx]) {
 
975
        case DBI_TYPE_BINARY:
 
976
        case DBI_TYPE_STRING:
 
977
            /* 
 
978
             * Result is more that 8 bytes - 
 
979
             * allocate additional memory
 
980
             */
 
981
            addr = row->field_values[idx].d_string = (char *) malloc(row->field_sizes[idx]);
 
982
            break;
 
983
        default:
 
984
            /* Prepare union to data copy */
 
985
            bzero((addr = &row->field_values[idx]), sizeof(dbi_data_t));
 
986
        }
 
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");
 
990
            return NULL;
 
991
        }
 
992
    }
 
993
    /* All columns buffer binded */
 
994
    return row;
 
995
}
 
996
 
 
997
void _dbd_free_row(dbi_result_t * result, dbi_row_t * row)
 
998
{
 
999
    unsigned int idx = 0;
 
1000
 
 
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);
 
1005
        }
 
1006
    }
 
1007
    free(row->field_values);
 
1008
    free(row->field_sizes);
 
1009
    free(row->field_flags);
 
1010
    free(row);
 
1011
}