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

« back to all changes in this revision

Viewing changes to drivers/pgsql/dbd_pgsql.c

  • Committer: Bazaar Package Importer
  • Author(s): David Parker
  • Date: 2004-02-01 14:33:06 UTC
  • Revision ID: james.westby@ubuntu.com-20040201143306-pmwubrx4d4jrq7om
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

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_pgsql.c: PostgreSQL database support (using libpq)
 
21
 * Copyright (C) 2001-2002, David A. Parker <david@neongoat.com>.
 
22
 * http://libdbi.sourceforge.net
 
23
 * 
 
24
 * $Id: dbd_pgsql.c,v 1.38 2004/01/04 00:43:20 mhoenicka Exp $
 
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
 
 
45
#include <dbi/dbi.h>
 
46
#include <dbi/dbi-dev.h>
 
47
#include <dbi/dbd.h>
 
48
 
 
49
#include <libpq-fe.h>
 
50
#include "dbd_pgsql.h"
 
51
 
 
52
static const dbi_info_t driver_info = {
 
53
        "pgsql",
 
54
        "PostgreSQL database support (using libpq)",
 
55
        "David A. Parker <david@neongoat.com>",
 
56
        "http://libdbi-drivers.sourceforge.net",
 
57
        "dbd_pgsql v" VERSION,
 
58
        __DATE__
 
59
};
 
60
 
 
61
static const char *custom_functions[] = {NULL}; // TODO
 
62
static const char *reserved_words[] = PGSQL_RESERVED_WORDS;
 
63
 
 
64
/* encoding strings, array is terminated by empty string */
 
65
static const char pgsql_encoding_hash[][16] = {
 
66
  /* from , to */
 
67
  "SQL_ASCII", "US-ASCII",
 
68
  "EUC_JP", "EUC-JP",
 
69
  "EUC_KR", "EUC-KR",
 
70
  "UNICODE", "UTF-8",
 
71
  "LATIN1", "ISO-8859-1",
 
72
  "LATIN2", "ISO-8859-2",
 
73
  "LATIN3", "ISO-8859-3",
 
74
  "LATIN4", "ISO-8859-4",
 
75
  "LATIN5", "ISO-8859-9",
 
76
  "LATIN6", "ISO-8859-10",
 
77
  "LATIN7", "ISO-8859-13",
 
78
  "LATIN8", "ISO-8859-14",
 
79
  "LATIN9", "ISO-8859-15",
 
80
  "LATIN10", "ISO-8859-16",
 
81
  "ISO-8859-5", "ISO-8859-5",
 
82
  "ISO-8859-6", "ISO-8859-6",
 
83
  "ISO-8859-7", "ISO-8859-7",
 
84
  "ISO-8859-8", "ISO-8859-8",
 
85
  "KOI8", "KOI8-R",
 
86
  "WIN", "windows-1251",
 
87
  "ALT", "IBM866",
 
88
  ""
 
89
};
 
90
 
 
91
/* forward declarations of internal functions */
 
92
void _translate_postgresql_type(unsigned int oid, unsigned short *type, unsigned int *attribs);
 
93
void _get_field_info(dbi_result_t *result);
 
94
void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx);
 
95
 
 
96
/* this function is available through the PostgreSQL client library, but it
 
97
   is not declared in any of their headers. I hope this won't break anything */
 
98
char *pg_encoding_to_char(int encoding_id);
 
99
 
 
100
 
 
101
/* real code starts here */
 
102
void dbd_register_driver(const dbi_info_t **_driver_info, const char ***_custom_functions, const char ***_reserved_words) {
 
103
        /* this is the first function called after the driver module is loaded into memory */
 
104
        *_driver_info = &driver_info;
 
105
        *_custom_functions = custom_functions;
 
106
        *_reserved_words = reserved_words;
 
107
}
 
108
 
 
109
int dbd_initialize(dbi_driver_t *driver) {
 
110
        /* perform any database-specific server initialization.
 
111
         * this is called right after dbd_register_driver().
 
112
         * return -1 on error, 0 on success. if -1 is returned, the driver will not
 
113
         * be added to the list of available drivers. */
 
114
        
 
115
        return 0;
 
116
}
 
117
 
 
118
int dbd_connect(dbi_conn_t *conn) {
 
119
        const char *host = dbi_conn_get_option(conn, "host");
 
120
        const char *username = dbi_conn_get_option(conn, "username");
 
121
        const char *password = dbi_conn_get_option(conn, "password");
 
122
        const char *dbname = dbi_conn_get_option(conn, "dbname");
 
123
        int port = dbi_conn_get_option_numeric(conn, "port");
 
124
 
 
125
        /* pgsql specific options */
 
126
        const char *options = dbi_conn_get_option(conn, "pgsql_options");
 
127
        const char *tty = dbi_conn_get_option(conn, "pgsql_tty");
 
128
 
 
129
        PGconn *pgconn;
 
130
        char *port_str;
 
131
        char *conninfo;
 
132
        char *conninfo_kludge;
 
133
 
 
134
        if (port > 0) asprintf(&port_str, "%d", port);
 
135
        else port_str = NULL;
 
136
 
 
137
        /* YUCK YUCK YUCK YUCK YUCK. stupid libpq. */
 
138
        if (host && port_str) asprintf(&conninfo_kludge, "host='%s' port='%s'", host, port_str);
 
139
        else if (host) asprintf(&conninfo_kludge, "host='%s'", host);
 
140
        else if (port_str) asprintf(&conninfo_kludge, "port='%s'", port_str);
 
141
        else conninfo_kludge = NULL;
 
142
 
 
143
        if (port_str) free(port_str);
 
144
        
 
145
        asprintf(&conninfo, "%s dbname='%s' user='%s' password='%s' options='%s' tty='%s'",
 
146
                conninfo_kludge ? conninfo_kludge : "", /* if we pass a NULL directly to the %s it will show up as "(null)" */
 
147
                dbname ? dbname : "",
 
148
                username ? username : "",
 
149
                password ? password : "",
 
150
                options ? options : "",
 
151
                tty ? tty : "");
 
152
 
 
153
        if (conninfo_kludge) free(conninfo_kludge);
 
154
 
 
155
        pgconn = PQconnectdb(conninfo);
 
156
        if (conninfo) free(conninfo);
 
157
        if (!pgconn) return -1;
 
158
 
 
159
        if (PQstatus(pgconn) == CONNECTION_BAD) {
 
160
                conn->connection = (void *)pgconn; // still need this set so _error_handler can grab information
 
161
                _error_handler(conn, DBI_ERROR_DBD);
 
162
                PQfinish(pgconn);
 
163
                conn->connection = NULL; // pgconn no longer valid
 
164
                return -2;
 
165
        }
 
166
        else {
 
167
                conn->connection = (void *)pgconn;
 
168
                if (dbname) conn->current_db = strdup(dbname);
 
169
        }
 
170
        
 
171
        return 0;
 
172
}
 
173
 
 
174
int dbd_disconnect(dbi_conn_t *conn) {
 
175
        if (conn->connection) PQfinish((PGconn *)conn->connection);
 
176
        return 0;
 
177
}
 
178
 
 
179
int dbd_fetch_row(dbi_result_t *result, unsigned long long rownum) {
 
180
        dbi_row_t *row = NULL;
 
181
 
 
182
        if (result->result_state == NOTHING_RETURNED) return -1;
 
183
        
 
184
        if (result->result_state == ROWS_RETURNED) {
 
185
                /* get row here */
 
186
                row = _dbd_row_allocate(result->numfields);
 
187
                _get_row_data(result, row, rownum);
 
188
                _dbd_row_finalize(result, row, rownum);
 
189
        }
 
190
        
 
191
        return 1; /* 0 on error, 1 on successful fetchrow */
 
192
}
 
193
 
 
194
int dbd_free_query(dbi_result_t *result) {
 
195
        PQclear((PGresult *)result->result_handle);
 
196
        return 0;
 
197
}
 
198
 
 
199
int dbd_goto_row(dbi_result_t *result, unsigned long long row) {
 
200
        /* libpq doesn't have to do anything, the row index is specified when
 
201
         * fetching fields */
 
202
        return 1;
 
203
}
 
204
 
 
205
int dbd_get_socket(dbi_conn_t *conn)
 
206
{
 
207
        PGconn *pgconn = (PGconn*) conn->connection;
 
208
 
 
209
        if(!pgconn) return -1;
 
210
 
 
211
        return PQsocket(pgconn);
 
212
}
 
213
 
 
214
const char *dbd_get_encoding(dbi_conn_t *conn){
 
215
 
 
216
        char* my_enc;
 
217
        PGconn *pgconn = (PGconn*) conn->connection;
 
218
        
 
219
        if(!pgconn) return NULL;
 
220
 
 
221
        /* this is somewhat murky as the pg_encoding_to_char()
 
222
         function is not declared properly by the PostgreSQL client
 
223
         library headers.  This may indicate that it is not supposed
 
224
         to be exported or that it may disappear without a trace
 
225
         eventually. If it breaks, use a query "SHOW CLIENT_ENCODING"
 
226
         instead */
 
227
        my_enc = pg_encoding_to_char(PQclientEncoding(pgconn));
 
228
 
 
229
        if (!my_enc) {
 
230
          return NULL;
 
231
        }
 
232
        else {
 
233
          int i = 0;
 
234
 
 
235
          /* loop over all even entries in hash and compare to my_enc */
 
236
          while (*pgsql_encoding_hash[i]) {
 
237
            if (!strcmp(pgsql_encoding_hash[i], my_enc)) {
 
238
              /* return corresponding odd entry */
 
239
              return pgsql_encoding_hash[i+1];
 
240
            }
 
241
            i+=2;
 
242
          }
 
243
 
 
244
          /* don't know how to translate, return original string */
 
245
          return my_enc;
 
246
        }
 
247
}
 
248
 
 
249
dbi_result_t *dbd_list_dbs(dbi_conn_t *conn, const char *pattern) {
 
250
        dbi_result_t *res;
 
251
        char *sql_cmd;
 
252
 
 
253
        if (pattern == NULL) {
 
254
                return dbd_query(conn, "SELECT datname FROM pg_database");
 
255
        }
 
256
        else {
 
257
                asprintf(&sql_cmd, "SELECT datname FROM pg_database WHERE datname LIKE '%s'", pattern);
 
258
                res = dbd_query(conn, sql_cmd);
 
259
                free(sql_cmd);
 
260
                return res;
 
261
        }
 
262
}
 
263
 
 
264
dbi_result_t *dbd_list_tables(dbi_conn_t *conn, const char *db, const char *pattern) {
 
265
        if (db == NULL) {
 
266
                return NULL;
 
267
        }
 
268
 
 
269
        if (pattern == NULL) {
 
270
                return (dbi_result_t *)dbi_conn_queryf((dbi_conn)conn, "SELECT relname FROM pg_class WHERE relname !~ '^pg_' AND relkind = 'r' AND relowner = (SELECT datdba FROM pg_database WHERE datname = '%s') ORDER BY relname", db);
 
271
        }
 
272
        else {
 
273
                return (dbi_result_t *)dbi_conn_queryf((dbi_conn)conn, "SELECT relname FROM pg_class WHERE relname !~ '^pg_' AND relname LIKE '%s' AND relkind = 'r' AND relowner = (SELECT datdba FROM pg_database WHERE datname = '%s') ORDER BY relname", pattern, db);
 
274
        }
 
275
}
 
276
 
 
277
int dbd_quote_string(dbi_driver_t *driver, const char *orig, char *dest) {
 
278
        /* foo's -> 'foo\'s' */
 
279
        int len;
 
280
 
 
281
        strcpy(dest, "'");
 
282
        len = PQescapeString(dest+1, orig, strlen(orig));
 
283
        strcat(dest, "'");
 
284
        
 
285
        return len+2;
 
286
}
 
287
 
 
288
dbi_result_t *dbd_query(dbi_conn_t *conn, const char *statement) {
 
289
        /* allocate a new dbi_result_t and fill its applicable members:
 
290
         * 
 
291
         * result_handle, numrows_matched, and numrows_changed.
 
292
         * everything else will be filled in by DBI */
 
293
        
 
294
        dbi_result_t *result;
 
295
        PGresult *res;
 
296
        int resstatus;
 
297
        
 
298
        res = PQexec((PGconn *)conn->connection, statement);
 
299
        if (res) resstatus = PQresultStatus(res);
 
300
        if (!res || ((resstatus != PGRES_COMMAND_OK) && (resstatus != PGRES_TUPLES_OK))) {
 
301
                PQclear(res);
 
302
                return NULL;
 
303
        }
 
304
 
 
305
        result = _dbd_result_create(conn, (void *)res, PQntuples(res), atol(PQcmdTuples(res)));
 
306
        _dbd_result_set_numfields(result, PQnfields((PGresult *)result->result_handle));
 
307
        _get_field_info(result);
 
308
 
 
309
        return result;
 
310
}
 
311
 
 
312
dbi_result_t *dbd_query_null(dbi_conn_t *conn, const unsigned char *statement, unsigned long st_length) {
 
313
        return NULL;
 
314
}
 
315
 
 
316
char *dbd_select_db(dbi_conn_t *conn, const char *db) {
 
317
  /* postgresql doesn't support switching databases without reconnecting */
 
318
  if (!db || !*db) {
 
319
    return NULL;
 
320
  }
 
321
 
 
322
  if (conn->connection) {
 
323
    PQfinish((PGconn *)conn->connection);
 
324
    conn->connection = NULL;
 
325
  }
 
326
 
 
327
  dbi_conn_set_option(conn, "dbname", db);
 
328
  if (dbd_connect(conn)) {
 
329
    return NULL;
 
330
  }
 
331
 
 
332
  return (char *)db;
 
333
}
 
334
 
 
335
int dbd_geterror(dbi_conn_t *conn, int *errno, char **errstr) {
 
336
        /* put error number into errno, error string into errstr
 
337
         * return 0 if error, 1 if errno filled, 2 if errstr filled, 3 if both errno and errstr filled */
 
338
        
 
339
        *errno = 0;
 
340
        *errstr = strdup(PQerrorMessage((PGconn *)conn->connection));
 
341
        
 
342
        return 2;
 
343
}
 
344
 
 
345
unsigned long long dbd_get_seq_last(dbi_conn_t *conn, const char *sequence) {
 
346
        unsigned long long seq_last = 0;
 
347
        char *sql_cmd;
 
348
        char *rawdata;
 
349
        dbi_result_t *result;
 
350
 
 
351
        asprintf(&sql_cmd, "SELECT currval('%s')", sequence);
 
352
        if (!sql_cmd) return 0;
 
353
        result = dbd_query(conn, sql_cmd);
 
354
        free(sql_cmd);
 
355
 
 
356
        if (result) {
 
357
                rawdata = PQgetvalue((PGresult *)result->result_handle, 0, 0);
 
358
                if (rawdata) {
 
359
                        seq_last = atoll(rawdata);
 
360
                }
 
361
                dbi_result_free((dbi_result)result);
 
362
        }
 
363
 
 
364
        return seq_last;
 
365
}
 
366
 
 
367
unsigned long long dbd_get_seq_next(dbi_conn_t *conn, const char *sequence) {
 
368
        unsigned long long seq_next = 0;
 
369
        char *sql_cmd;
 
370
        char *rawdata;
 
371
        dbi_result_t *result;
 
372
 
 
373
        asprintf(&sql_cmd, "SELECT nextval('%s')", sequence);
 
374
        if (!sql_cmd) return 0;
 
375
        result = dbd_query(conn, sql_cmd);
 
376
        free(sql_cmd);
 
377
 
 
378
        if (result) {   
 
379
                rawdata = PQgetvalue((PGresult *)result->result_handle, 0, 0);
 
380
                if (rawdata) {
 
381
                        seq_next = atoll(rawdata);
 
382
                }
 
383
                dbi_result_free((dbi_result)result);
 
384
        }
 
385
 
 
386
        return seq_next;
 
387
}
 
388
 
 
389
int dbd_ping(dbi_conn_t *conn) {
 
390
        PGconn *pgsql = (PGconn *)conn->connection;
 
391
 
 
392
        PQexec(pgsql, "SELECT 1");
 
393
 
 
394
        if (PQstatus(pgsql) == CONNECTION_OK) {
 
395
                return 1;
 
396
        }
 
397
 
 
398
        PQreset(pgsql); // attempt a reconnection
 
399
        
 
400
        if (PQstatus(pgsql) == CONNECTION_OK) {
 
401
                return 1;
 
402
        }
 
403
 
 
404
        return 0;
 
405
}
 
406
 
 
407
/* CORE POSTGRESQL DATA FETCHING STUFF */
 
408
 
 
409
void _translate_postgresql_type(unsigned int oid, unsigned short *type, unsigned int *attribs) {
 
410
        unsigned int _type = 0;
 
411
        unsigned int _attribs = 0;
 
412
 
 
413
        switch (oid) {
 
414
                case PG_TYPE_CHAR:
 
415
                        _type = DBI_TYPE_INTEGER;
 
416
                        _attribs |= DBI_INTEGER_SIZE1;
 
417
                        break;
 
418
                case PG_TYPE_INT2:
 
419
                        _type = DBI_TYPE_INTEGER;
 
420
                        _attribs |= DBI_INTEGER_SIZE2;
 
421
                        break;
 
422
                case PG_TYPE_INT4:
 
423
                        _type = DBI_TYPE_INTEGER;
 
424
                        _attribs |= DBI_INTEGER_SIZE4;
 
425
                        break;
 
426
                case PG_TYPE_INT8:
 
427
                        _type = DBI_TYPE_INTEGER;
 
428
                        _attribs |= DBI_INTEGER_SIZE8;
 
429
                        break;
 
430
                case PG_TYPE_OID:
 
431
                        _type = DBI_TYPE_INTEGER;
 
432
                        _attribs |= DBI_INTEGER_SIZE8;
 
433
                        _attribs |= DBI_INTEGER_UNSIGNED;
 
434
                        break;
 
435
                        
 
436
                case PG_TYPE_FLOAT4:
 
437
                        _type = DBI_TYPE_DECIMAL;
 
438
                        _attribs |= DBI_DECIMAL_SIZE4;
 
439
                        break;
 
440
                case PG_TYPE_FLOAT8:
 
441
                        _type = DBI_TYPE_DECIMAL;
 
442
                        _attribs |= DBI_DECIMAL_SIZE8;
 
443
                        break;
 
444
                case PG_TYPE_DATE:
 
445
                       _type = DBI_TYPE_DATETIME;
 
446
                       _attribs |= DBI_DATETIME_DATE;
 
447
                       break;
 
448
                case PG_TYPE_TIME:
 
449
                       _type = DBI_TYPE_DATETIME;
 
450
                       _attribs |= DBI_DATETIME_TIME;
 
451
                       break;
 
452
        case PG_TYPE_DATETIME:
 
453
        case PG_TYPE_TIMESTAMP:
 
454
                        _type = DBI_TYPE_DATETIME;
 
455
                        _attribs |= DBI_DATETIME_DATE;
 
456
                        _attribs |= DBI_DATETIME_TIME;
 
457
                        break;
 
458
                case PG_TYPE_NAME:
 
459
                case PG_TYPE_TEXT:
 
460
                case PG_TYPE_CHAR2:
 
461
                case PG_TYPE_CHAR4:
 
462
                case PG_TYPE_CHAR8:
 
463
                case PG_TYPE_BPCHAR:
 
464
                case PG_TYPE_VARCHAR:
 
465
                        _type = DBI_TYPE_STRING;
 
466
                        break;
 
467
 
 
468
                case PG_TYPE_BYTEA:
 
469
                        _type = DBI_TYPE_BINARY;
 
470
                        break;
 
471
                        
 
472
                default:
 
473
                        _type = DBI_TYPE_STRING;
 
474
                        break;
 
475
        }
 
476
        
 
477
        *type = _type;
 
478
        *attribs = _attribs;
 
479
}
 
480
 
 
481
void _get_field_info(dbi_result_t *result) {
 
482
        unsigned int idx = 0;
 
483
        unsigned int pgOID = 0;
 
484
        char *fieldname;
 
485
        unsigned short fieldtype;
 
486
        unsigned int fieldattribs;
 
487
        
 
488
        while (idx < result->numfields) {
 
489
                pgOID = PQftype((PGresult *)result->result_handle, idx);
 
490
                fieldname = PQfname((PGresult *)result->result_handle, idx);
 
491
                _translate_postgresql_type(pgOID, &fieldtype, &fieldattribs);
 
492
                _dbd_result_add_field(result, idx, fieldname, fieldtype, fieldattribs);
 
493
                idx++;
 
494
        }
 
495
}
 
496
 
 
497
void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx) {
 
498
        int curfield = 0;
 
499
        char *raw = NULL;
 
500
        unsigned long long strsize = 0;
 
501
        unsigned long sizeattrib;
 
502
        dbi_data_t *data;
 
503
 
 
504
        while (curfield < result->numfields) {
 
505
                raw = PQgetvalue((PGresult *)result->result_handle, rowidx, curfield);
 
506
                strsize = (unsigned long long) PQfmod((PGresult *)result->result_handle, curfield);
 
507
                data = &row->field_values[curfield];
 
508
 
 
509
                row->field_sizes[curfield] = 0;
 
510
                /* will be set to strlen later on for strings */
 
511
                
 
512
                if (PQgetisnull((PGresult *)result->result_handle, rowidx, curfield) == 1) {
 
513
                        curfield++;
 
514
                        continue;
 
515
                }
 
516
                
 
517
                switch (result->field_types[curfield]) {
 
518
                        case DBI_TYPE_INTEGER:
 
519
                                sizeattrib = _isolate_attrib(result->field_attribs[curfield], DBI_INTEGER_SIZE1, DBI_INTEGER_SIZE8);
 
520
                                switch (sizeattrib) {
 
521
                                        case DBI_INTEGER_SIZE1:
 
522
                                                data->d_char = (char) atol(raw); break;
 
523
                                        case DBI_INTEGER_SIZE2:
 
524
                                                data->d_short = (short) atol(raw); break;
 
525
                                        case DBI_INTEGER_SIZE3:
 
526
                                        case DBI_INTEGER_SIZE4:
 
527
                                                data->d_long = (long) atol(raw); break;
 
528
                                        case DBI_INTEGER_SIZE8:
 
529
                                                data->d_longlong = (long long) atoll(raw); break; /* hah, wonder if that'll work */
 
530
                                        default:
 
531
                                                break;
 
532
                                }
 
533
                                break;
 
534
                        case DBI_TYPE_DECIMAL:
 
535
                                sizeattrib = _isolate_attrib(result->field_attribs[curfield], DBI_DECIMAL_SIZE4, DBI_DECIMAL_SIZE8);
 
536
                                switch (sizeattrib) {
 
537
                                        case DBI_DECIMAL_SIZE4:
 
538
                                                data->d_float = (float) strtod(raw, NULL); break;
 
539
                                        case DBI_DECIMAL_SIZE8:
 
540
                                                data->d_double = (double) strtod(raw, NULL); break;
 
541
                                        default:
 
542
                                                break;
 
543
                                }
 
544
                                break;
 
545
                        case DBI_TYPE_STRING:
 
546
                                data->d_string = strdup(raw);
 
547
                                row->field_sizes[curfield] = strsize;
 
548
                                break;
 
549
                        case DBI_TYPE_BINARY:
 
550
                                row->field_sizes[curfield] = strsize;
 
551
                                data->d_string = malloc(strsize);
 
552
                                memcpy(data->d_string, raw, strsize);
 
553
                                break;
 
554
                                
 
555
                        case DBI_TYPE_DATETIME:
 
556
                                sizeattrib = _isolate_attrib(result->field_attribs[curfield], DBI_DATETIME_DATE, DBI_DATETIME_TIME);
 
557
                                data->d_datetime = _dbd_parse_datetime(raw, sizeattrib);
 
558
                                break;
 
559
                                
 
560
                        default:
 
561
                                break;
 
562
                }
 
563
                
 
564
                curfield++;
 
565
        }
 
566
}
 
567