1 /*
2 * libdbi - database independent abstraction layer for C.
3 * Copyright (C) 2001-2003, 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 * $Id: dbi_main.c,v 1.103 2013/01/24 22:10:18 mhoenicka Exp $
21 */
22
23 /* silence the deprecated warnings as this lib must implement and call
24 the deprecated functions for the time being */
25 #define LIBDBI_API_DEPRECATED /**/
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 /* #define _GNU_SOURCE */ /* we need the asprintf() prototype but _GNU_SOURCE should be defined in config.h */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <strings.h> /* for strcasecmp */
38 #include <sys/types.h>
39 #include <stddef.h>
40
41 /* Dlopen stuff */
42 #if HAVE_LTDL_H
43 #include <ltdl.h>
44 #define my_dlopen(foo,bar) lt_dlopen(foo)
45 #define my_dlsym lt_dlsym
46 #define my_dlclose lt_dlclose
47 #define my_dlerror lt_dlerror
48
49 #elif HAVE_MACH_O_DYLD_H
50 #include <mach-o/dyld.h>
51 static void * dyld_dlopen(const char * file);
52 static void * dyld_dlsym(void * hand, const char * name);
53 static int dyld_dlclose(void * hand);
54 static const char * dyld_dlerror();
55 #define my_dlopen(foo,bar) dyld_dlopen(foo)
56 #define my_dlsym dyld_dlsym
57 #define my_dlerror dyld_dlerror
58 #define my_dlclose dyld_dlclose
59
60 #elif __MINGW32__
61 #include <windows.h>
62 void *win_dlopen(const char*, int);
63 void *win_dlsym(void *, const char*);
64 int win_dlclose(void *);
65 char *win_dlerror();
66 /* just for compiling support,if anyone has used these masks in code. The MODE argument to `dlopen' contains one of the following: */
67 #define RTLD_LAZY 0x001 /* Lazy function call binding. */
68 #define RTLD_NOW 0x002 /* Immediate function call binding. */
69 #define RTLD_BINDING_MASK 0x003 /* Mask of binding time value. */
70 #define my_dlopen(foo,bar) win_dlopen(foo,bar)
71 #define my_dlsym win_dlsym
72 #define my_dlclose win_dlclose
73 #define my_dlerror win_dlerror
74
75 #elif HAVE_DLFCN_H
76 #include <dlfcn.h>
77 #define my_dlopen dlopen
78 #define my_dlsym dlsym
79 #define my_dlclose dlclose
80 #define my_dlerror dlerror
81
82 #else
83 #error no dynamic loading support
84 #endif
85 /* end dlopen stuff */
86
87 #include <sys/stat.h>
88 #ifdef HAVE_UNISTD_H
89 #include <unistd.h>
90 #endif
91 #include <dirent.h>
92
93 #include <math.h>
94 #include <limits.h>
95
96 #include <dbi/dbi.h>
97 #include <dbi/dbi-dev.h>
98
99 #ifdef __MINGW32__
100 # define DBI_PATH_SEPARATOR "\\"
101 # ifndef DBI_DRIVER_DIR
102 # define DBI_DRIVER_DIR "c:\\libdbi\\lib\\dbd" /* use this as the default */
103 # endif
104 # else
105 # define DBI_PATH_SEPARATOR "/"
106 # ifndef DBI_DRIVER_DIR
107 # define DBI_DRIVER_DIR "/usr/local/lib/dbd" /* use this as the default */
108 # endif
109 #endif
110
111 #ifndef DLSYM_PREFIX
112 #define DLSYM_PREFIX ""
113 #endif
114
115 #ifndef RTLD_NEXT
116 #define RTLD_NEXT ((void *) -1) /* taken from FreeBSD, just a compile helper */
117 #endif
118
119 /* declarations of optional external functions */
120 #if !HAVE_DECL_VASPRINTF
121 int vasprintf(char **result, const char *format, va_list args);
122 #endif
123 #if !HAVE_DECL_ASPRINTF
124 int asprintf(char **result, const char *format, ...);
125 #endif
126
127 /* declarations for internal functions -- anything declared as static won't be accessible by name from client programs */
128 static dbi_driver_t *_get_driver(const char *filename, dbi_inst_t *inst);
129 static void _free_custom_functions(dbi_driver_t *driver);
130 static dbi_option_t *_find_or_create_option_node(dbi_conn Conn, const char *key);
131 static int _update_internal_conn_list(dbi_conn_t *conn, int operation);
132 static void _free_caps(_capability_t *caproot);
133 static const char *_get_option(dbi_conn Conn, const char *key, int aggressive);
134 static int _get_option_numeric(dbi_conn Conn, const char *key, int aggressive);
135 static unsigned int _parse_versioninfo(const char *version);
136 static int _safe_dlclose(dbi_driver_t *driver);
137
138 void _error_handler(dbi_conn_t *conn, dbi_error_flag errflag);
139 extern int _disjoin_from_conn(dbi_result_t *result);
140
141 dbi_result dbi_conn_queryf(dbi_conn Conn, const char *formatstr, ...) __attribute__ ((format (printf, 2, 3)));
142 int dbi_conn_set_error(dbi_conn Conn, int errnum, const char *formatstr, ...) __attribute__ ((format (printf, 3, 4)));
143
144 /* must not be called "ERROR" due to a name clash on Windoze */
145 static const char *my_ERROR = "ERROR";
146 static dbi_inst dbi_inst_legacy;
147
148
149 /* XXX DBI CORE FUNCTIONS XXX */
150
dbi_initialize_r(const char * driverdir,dbi_inst * pInst)151 int dbi_initialize_r(const char *driverdir, dbi_inst *pInst) {
152 dbi_inst_t *inst;
153 DIR *dir;
154 struct dirent *driver_dirent = NULL;
155 struct stat statbuf;
156 char fullpath[FILENAME_MAX];
157 char *effective_driverdir;
158
159 int num_loaded = 0;
160 *pInst = NULL; /* use a defined value if the function fails */
161 dbi_driver_t *driver = NULL;
162 dbi_driver_t *prevdriver = NULL;
163 #if HAVE_LTDL_H
164 (void)lt_dlinit();
165 #endif
166 /* init the instance */
167 inst = malloc(sizeof(dbi_inst_t));
168 if (!inst) {
169 return -1;
170 }
171 *pInst = (void*) inst;
172 inst->rootdriver = NULL;
173 inst->rootconn = NULL;
174 inst->dbi_verbosity = 1; /* TODO: is this really the correct default? */
175 /* end instance init */
176 effective_driverdir = (driverdir ? (char *)driverdir : DBI_DRIVER_DIR);
177 dir = opendir(effective_driverdir);
178
179 if (dir == NULL) {
180 return -1;
181 }
182 else {
183 struct dirent *buffer;
184 size_t buffer_size;
185 int status;
186
187 /* allocate memory for readdir_r(3) */
188 buffer_size = _dirent_buf_size(dir);
189 if (buffer_size == 0) {
190 return -1;
191 }
192
193 buffer = (struct dirent *) malloc (buffer_size);
194 if (buffer == NULL) {
195 return -1;
196 }
197
198 memset (buffer, 0, buffer_size);
199
200 status = 0;
201 while (42) { /* yes, we all admire Douglas Adams */
202 driver_dirent = NULL;
203 status = readdir_r (dir, buffer, &driver_dirent);
204 if (status != 0 || driver_dirent == NULL) {
205 break;
206 }
207
208 driver = NULL;
209 snprintf(fullpath, FILENAME_MAX, "%s%s%s", effective_driverdir, DBI_PATH_SEPARATOR, driver_dirent->d_name);
210 if ((stat(fullpath, &statbuf) == 0) && S_ISREG(statbuf.st_mode) && strrchr(driver_dirent->d_name, '.') && (!strcmp(strrchr(driver_dirent->d_name, '.'), DRIVER_EXT))) {
211 /* file is a stat'able regular file that ends in .so (or appropriate dynamic library extension) */
212 driver = _get_driver(fullpath, inst);
213 if (driver && (driver->functions->initialize(driver) != -1)) {
214 if (!inst->rootdriver) {
215 inst->rootdriver = driver;
216 }
217 if (prevdriver) {
218 prevdriver->next = driver;
219 }
220 prevdriver = driver;
221 num_loaded++;
222 }
223 else {
224 if (driver && driver->dlhandle) _safe_dlclose(driver);
225 if (driver && driver->functions) free(driver->functions);
226 if (driver) free(driver);
227 driver = NULL; /* don't include in linked list */
228 if (inst->dbi_verbosity) fprintf(stderr, "libdbi: Failed to load driver: %s\n", fullpath);
229 }
230 }
231 } /* while (42) */
232 closedir(dir);
233 free(buffer);
234 }
235
236 return num_loaded;
237 }
238
dbi_initialize(const char * driverdir)239 int dbi_initialize(const char *driverdir) {
240 return (dbi_initialize_r(driverdir, &dbi_inst_legacy));
241 }
242
dbi_shutdown_r(dbi_inst Inst)243 void dbi_shutdown_r(dbi_inst Inst) {
244 dbi_inst_t *inst = (dbi_inst_t*) Inst;
245 dbi_conn_t *curconn = inst->rootconn;
246 dbi_conn_t *nextconn;
247
248 dbi_driver_t *curdriver = inst->rootdriver;
249 dbi_driver_t *nextdriver;
250
251 while (curconn) {
252 nextconn = curconn->next;
253 dbi_conn_close((dbi_conn)curconn);
254 curconn = nextconn;
255 }
256
257 while (curdriver) {
258 nextdriver = curdriver->next;
259 curdriver->functions->finalize(curdriver);
260 _safe_dlclose(curdriver);
261 free(curdriver->functions);
262 _free_custom_functions(curdriver);
263 _free_caps(curdriver->caps);
264 free(curdriver->filename);
265 free(curdriver);
266 curdriver = nextdriver;
267 }
268 #if HAVE_LTDL_H
269 (void)lt_dlexit();
270 #endif
271 free(inst);
272 }
273
dbi_shutdown()274 void dbi_shutdown() {
275 dbi_shutdown_r(dbi_inst_legacy);
276 }
277
dbi_version()278 const char *dbi_version() {
279 return "libdbi v" VERSION;
280 }
281
dbi_version_numeric()282 unsigned int dbi_version_numeric() {
283 return (unsigned int)LIBDBI_VERSION;
284 }
285
dbi_set_verbosity_r(int verbosity,dbi_inst Inst)286 int dbi_set_verbosity_r(int verbosity, dbi_inst Inst) {
287 dbi_inst_t *inst = (dbi_inst_t*) Inst;
288 /* whether or not to spew stderr messages when something bad happens (and
289 * isn't handled through the normal connection-oriented DBI error
290 * mechanisms) */
291
292 int prev = inst->dbi_verbosity;
293 inst->dbi_verbosity = verbosity;
294 return prev;
295 }
dbi_set_verbosity(int verbosity)296 int dbi_set_verbosity(int verbosity) {
297 return dbi_set_verbosity_r(verbosity, dbi_inst_legacy);
298 }
299
300 /* XXX DRIVER FUNCTIONS XXX */
301
dbi_driver_list_r(dbi_driver Current,dbi_inst Inst)302 dbi_driver dbi_driver_list_r(dbi_driver Current, dbi_inst Inst) {
303 dbi_inst_t *inst = (dbi_inst_t*) Inst;
304 dbi_driver_t *current = Current;
305
306 if (current == NULL) {
307 return (dbi_driver)inst->rootdriver;
308 }
309
310 return (dbi_driver)current->next;
311 }
dbi_driver_list(dbi_driver Current)312 dbi_driver dbi_driver_list(dbi_driver Current) {
313 return dbi_driver_list_r(Current, dbi_inst_legacy);
314 }
315
dbi_driver_open_r(const char * name,dbi_inst Inst)316 dbi_driver dbi_driver_open_r(const char *name, dbi_inst Inst) {
317 dbi_inst_t *inst = (dbi_inst_t*) Inst;
318 dbi_driver_t *driver = inst->rootdriver;
319
320 while (driver && strcasecmp(name, driver->info->name)) {
321 driver = driver->next;
322 }
323
324 return driver;
325 }
dbi_driver_open(const char * name)326 dbi_driver dbi_driver_open(const char *name) {
327 return dbi_driver_open_r(name, dbi_inst_legacy);
328 }
329
dbi_driver_get_instance(dbi_driver Driver)330 dbi_inst dbi_driver_get_instance(dbi_driver Driver) {
331 dbi_driver_t *driver = Driver;
332
333 if (!driver) return NULL;
334
335 return driver->dbi_inst;
336 }
337
dbi_driver_is_reserved_word(dbi_driver Driver,const char * word)338 int dbi_driver_is_reserved_word(dbi_driver Driver, const char *word) {
339 unsigned int idx = 0;
340 dbi_driver_t *driver = Driver;
341
342 if (!driver) return 0;
343
344 while (driver->reserved_words[idx]) {
345 if (strcasecmp(word, driver->reserved_words[idx]) == 0) {
346 return 1;
347 }
348 idx++;
349 }
350 return 0;
351 }
352
dbi_driver_specific_function(dbi_driver Driver,const char * name)353 void *dbi_driver_specific_function(dbi_driver Driver, const char *name) {
354 dbi_driver_t *driver = Driver;
355 dbi_custom_function_t *custom;
356
357 if (!driver) return NULL;
358
359 custom = driver->custom_functions;
360
361 while (custom && strcasecmp(name, custom->name)) {
362 custom = custom->next;
363 }
364
365 return custom ? custom->function_pointer : NULL;
366 }
367
dbi_driver_cap_get(dbi_driver Driver,const char * capname)368 int dbi_driver_cap_get(dbi_driver Driver, const char *capname) {
369 dbi_driver_t *driver = Driver;
370 _capability_t *cap;
371
372 if (!driver) {
373 return 0;
374 }
375
376 cap = driver->caps;
377
378 while (cap && strcmp(capname, cap->name)) {
379 cap = cap->next;
380 }
381
382 return cap ? cap->value : 0;
383 }
384
dbi_conn_cap_get(dbi_conn Conn,const char * capname)385 int dbi_conn_cap_get(dbi_conn Conn, const char *capname) {
386 dbi_conn_t *conn = Conn;
387 _capability_t *cap;
388
389 if (!conn) return 0;
390
391 cap = conn->caps;
392
393 while (cap && strcmp(capname, cap->name)) {
394 cap = cap->next;
395 }
396
397 return cap ? cap->value : dbi_driver_cap_get((dbi_driver)conn->driver, capname);
398 }
399
400 /* DRIVER: informational functions */
401
dbi_driver_get_name(dbi_driver Driver)402 const char *dbi_driver_get_name(dbi_driver Driver) {
403 dbi_driver_t *driver = Driver;
404
405 if (!driver) return my_ERROR;
406
407 return driver->info->name;
408 }
409
dbi_driver_get_filename(dbi_driver Driver)410 const char *dbi_driver_get_filename(dbi_driver Driver) {
411 dbi_driver_t *driver = Driver;
412
413 if (!driver) return my_ERROR;
414
415 return driver->filename;
416 }
417
dbi_driver_get_description(dbi_driver Driver)418 const char *dbi_driver_get_description(dbi_driver Driver) {
419 dbi_driver_t *driver = Driver;
420
421 if (!driver) return my_ERROR;
422
423 return driver->info->description;
424 }
425
dbi_driver_get_maintainer(dbi_driver Driver)426 const char *dbi_driver_get_maintainer(dbi_driver Driver) {
427 dbi_driver_t *driver = Driver;
428
429 if (!driver) return my_ERROR;
430
431 return driver->info->maintainer;
432 }
433
dbi_driver_get_url(dbi_driver Driver)434 const char *dbi_driver_get_url(dbi_driver Driver) {
435 dbi_driver_t *driver = Driver;
436
437 if (!driver) return my_ERROR;
438
439 return driver->info->url;
440 }
441
dbi_driver_get_version(dbi_driver Driver)442 const char *dbi_driver_get_version(dbi_driver Driver) {
443 dbi_driver_t *driver = Driver;
444
445 if (!driver) return my_ERROR;
446
447 return driver->info->version;
448 }
449
dbi_driver_get_date_compiled(dbi_driver Driver)450 const char *dbi_driver_get_date_compiled(dbi_driver Driver) {
451 dbi_driver_t *driver = Driver;
452
453 if (!driver) return my_ERROR;
454
455 return driver->info->date_compiled;
456 }
457
458 /* DEPRECATED. Use dbi_conn_quote_string_copy instead */
dbi_driver_quote_string_copy(dbi_driver Driver,const char * orig,char ** newquoted)459 size_t dbi_driver_quote_string_copy(dbi_driver Driver, const char *orig, char **newquoted) {
460 dbi_driver_t *driver = Driver;
461 char *newstr;
462 size_t newlen;
463
464 if (!driver || !orig || !newquoted) return 0;
465
466 newstr = malloc((strlen(orig)*2)+4+1); /* worst case, we have to escape every character and add 2*2 surrounding quotes */
467
468 if (!newstr) {
469 return 0;
470 }
471
472 newlen = driver->functions->quote_string(driver, orig, newstr);
473 if (!newlen) {
474 free(newstr);
475 return 0;
476 }
477
478 *newquoted = newstr;
479
480 return newlen;
481 }
482
483 /* DEPRECATED. Use dbi_conn_quote_string instead */
dbi_driver_quote_string(dbi_driver Driver,char ** orig)484 size_t dbi_driver_quote_string(dbi_driver Driver, char **orig) {
485 char *temp = NULL;
486 char *newstr = NULL;
487 size_t newlen;
488
489 if (!orig || !*orig) {
490 return 0;
491 }
492
493 newlen = dbi_driver_quote_string_copy(Driver, *orig, &newstr);
494 if (!newlen) {
495 /* in case of an error, leave the original string alone */
496 return 0;
497 }
498
499 temp = *orig;
500 *orig = newstr;
501 free(temp); /* original unescaped string */
502
503 return newlen;
504 }
505
dbi_driver_encoding_from_iana(dbi_driver Driver,const char * iana_encoding)506 const char* dbi_driver_encoding_from_iana(dbi_driver Driver, const char* iana_encoding) {
507 dbi_driver_t *driver = Driver;
508
509 if (!driver) {
510 return NULL;
511 }
512
513 return driver->functions->encoding_from_iana(iana_encoding);
514 }
515
dbi_driver_encoding_to_iana(dbi_driver Driver,const char * db_encoding)516 const char* dbi_driver_encoding_to_iana(dbi_driver Driver, const char* db_encoding) {
517 dbi_driver_t *driver = Driver;
518
519 if (!driver) {
520 return NULL;
521 }
522
523 return driver->functions->encoding_to_iana(db_encoding);
524 }
525
526
527 /* XXX DRIVER FUNCTIONS XXX */
528
dbi_conn_new_r(const char * name,dbi_inst Inst)529 dbi_conn dbi_conn_new_r(const char *name, dbi_inst Inst) {
530 dbi_driver driver;
531 dbi_conn conn;
532
533 driver = dbi_driver_open_r(name, Inst);
534 conn = dbi_conn_open(driver);
535
536 return conn;
537 }
dbi_conn_new(const char * name)538 dbi_conn dbi_conn_new(const char *name) {
539 return (dbi_conn_new_r(name, dbi_inst_legacy));
540 }
541
dbi_conn_open(dbi_driver Driver)542 dbi_conn dbi_conn_open(dbi_driver Driver) {
543 dbi_driver_t *driver = Driver;
544 dbi_conn_t *conn;
545
546 if (!driver) {
547 return NULL;
548 }
549
550 conn = malloc(sizeof(dbi_conn_t));
551 if (!conn) {
552 return NULL;
553 }
554 conn->driver = driver;
555 conn->options = NULL;
556 conn->caps = NULL;
557 conn->connection = NULL;
558 conn->current_db = NULL;
559 conn->error_flag = DBI_ERROR_NONE; /* for legacy code only */
560 conn->error_number = DBI_ERROR_NONE;
561 conn->error_message = NULL;
562 conn->full_errmsg = NULL;
563 conn->error_handler = NULL;
564 conn->error_handler_argument = NULL;
565 _update_internal_conn_list(conn, 1);
566 conn->results = NULL;
567 conn->results_size = conn->results_used = 0;
568
569 return (dbi_conn)conn;
570 }
571
dbi_conn_disjoin_results(dbi_conn Conn)572 int dbi_conn_disjoin_results(dbi_conn Conn) {
573 dbi_conn_t *conn = Conn;
574 int errors = 0;
575 int idx;
576
577 if (!conn) return 0;
578
579 for (idx = conn->results_used-1; idx >= 0; idx--) {
580 if (dbi_result_disjoin((dbi_result)conn->results[idx]) < 0) {
581 errors--;
582 }
583 }
584
585 return errors;
586 }
587
dbi_conn_close(dbi_conn Conn)588 void dbi_conn_close(dbi_conn Conn) {
589 dbi_conn_t *conn = Conn;
590
591 if (!conn || !(conn->connection)) return;
592
593 _update_internal_conn_list(conn, -1);
594
595 conn->driver->functions->disconnect(conn);
596 conn->driver = NULL;
597 dbi_conn_clear_options(Conn);
598 _free_caps(conn->caps);
599 conn->connection = NULL;
600
601 if (conn->current_db) free(conn->current_db);
602 if (conn->error_message) free(conn->error_message);
603 if (conn->full_errmsg) free(conn->full_errmsg);
604 conn->error_number = 0;
605
606 conn->error_handler = NULL;
607 conn->error_handler_argument = NULL;
608 free(conn->results);
609
610 free(conn);
611
612 }
613
dbi_conn_get_driver(dbi_conn Conn)614 dbi_driver dbi_conn_get_driver(dbi_conn Conn) {
615 dbi_conn_t *conn = Conn;
616
617 if (!conn) return NULL;
618
619 return conn->driver;
620 }
621
dbi_conn_error(dbi_conn Conn,const char ** errmsg_dest)622 int dbi_conn_error(dbi_conn Conn, const char **errmsg_dest) {
623 dbi_conn_t *conn = Conn;
624 char number_portion[20];
625
626 if (errmsg_dest) {
627 if (conn->full_errmsg) free(conn->full_errmsg);
628
629 if (conn->error_number) {
630 snprintf(number_portion, 20, "%d: ", conn->error_number);
631 }
632 else {
633 number_portion[0] = '\0';
634 }
635
636 asprintf(&(conn->full_errmsg), "%s%s", number_portion, conn->error_message ? conn->error_message : "");
637 *errmsg_dest = conn->full_errmsg;
638 }
639
640 return conn->error_number;
641 }
642
dbi_conn_error_handler(dbi_conn Conn,dbi_conn_error_handler_func function,void * user_argument)643 void dbi_conn_error_handler(dbi_conn Conn, dbi_conn_error_handler_func function, void *user_argument) {
644 dbi_conn_t *conn = Conn;
645 conn->error_handler = function;
646 if (function == NULL) {
647 conn->error_handler_argument = NULL;
648 }
649 else {
650 conn->error_handler_argument = user_argument;
651 }
652 }
653
654 /* DEPRECATED */
dbi_conn_error_flag(dbi_conn Conn)655 dbi_error_flag dbi_conn_error_flag(dbi_conn Conn) {
656 dbi_conn_t *conn = Conn;
657 return conn->error_flag;
658 }
659
660 /* this function allows applications to set their own error messages
661 and display them through the libdbi API */
dbi_conn_set_error(dbi_conn Conn,int errnum,const char * formatstr,...)662 int dbi_conn_set_error(dbi_conn Conn, int errnum, const char *formatstr, ...) {
663 dbi_conn_t *conn = Conn;
664 char *msg;
665 int len;
666 va_list ap;
667 int trigger_callback;
668
669 if (!conn) return 0;
670
671 trigger_callback = dbi_conn_get_option_numeric(Conn, "UserErrorTriggersCallback");
672
673 va_start(ap, formatstr);
674 len = vasprintf(&msg, formatstr, ap);
675 va_end(ap);
676
677 if (conn->error_message) free(conn->error_message);
678 conn->error_message = msg;
679 conn->error_number = errnum;
680 conn->error_flag = DBI_ERROR_USER;
681
682 if (trigger_callback && (conn->error_handler != NULL)) {
683 /* trigger the external callback function */
684 conn->error_handler((dbi_conn)conn, conn->error_handler_argument);
685 }
686
687 return len;
688 }
689
690 /* CONN: quoting functions. These functions escape SQL special
691 characters and surround the resulting string with appropriate
692 quotes to insert it into a SQL query string */
693
dbi_conn_quote_string_copy(dbi_conn Conn,const char * orig,char ** newquoted)694 size_t dbi_conn_quote_string_copy(dbi_conn Conn, const char *orig, char **newquoted) {
695 dbi_conn_t *conn = Conn;
696 char *newstr;
697 size_t newlen;
698
699 if (!conn) {
700 return 0;
701 }
702
703 _reset_conn_error(conn);
704
705 if (!orig || !newquoted) {
706 _error_handler(conn, DBI_ERROR_BADPTR);
707 return 0;
708 }
709
710 newstr = malloc((strlen(orig)*2)+4+1); /* worst case, we have to escape every character and add 2*2 surrounding quotes */
711
712 if (!newstr) {
713 _error_handler(conn, DBI_ERROR_NOMEM);
714 return 0;
715 }
716
717 newlen = conn->driver->functions->conn_quote_string(conn, orig, newstr);
718 if (!newlen) {
719 free(newstr);
720 _error_handler(conn, DBI_ERROR_NOMEM);
721 return 0;
722 }
723
724 *newquoted = newstr;
725
726 return newlen;
727 }
728
dbi_conn_quote_string(dbi_conn Conn,char ** orig)729 size_t dbi_conn_quote_string(dbi_conn Conn, char **orig) {
730 dbi_conn_t *conn = Conn;
731 char *temp = NULL;
732 char *newstr = NULL;
733 size_t newlen;
734
735 if (!conn) {
736 return 0;
737 }
738
739 _reset_conn_error(conn);
740
741 if (!orig || !*orig) {
742 _error_handler(conn, DBI_ERROR_BADPTR);
743 return 0;
744 }
745
746 newlen = dbi_conn_quote_string_copy(Conn, *orig, &newstr);
747 if (!newlen) {
748 /* leave original string alone in case of an error */
749 /* error number was set by called function */
750 return 0;
751 }
752 temp = *orig;
753 *orig = newstr;
754 free(temp); /* original unescaped string */
755
756 return newlen;
757 }
758
dbi_conn_quote_binary_copy(dbi_conn Conn,const unsigned char * orig,size_t from_length,unsigned char ** ptr_dest)759 size_t dbi_conn_quote_binary_copy(dbi_conn Conn, const unsigned char *orig, size_t from_length, unsigned char **ptr_dest) {
760 unsigned char *temp = NULL;
761 size_t newlen;
762 dbi_conn_t *conn = Conn;
763
764 if (!conn) {
765 return 0;
766 }
767
768 _reset_conn_error(conn);
769
770 if (!orig || !ptr_dest) {
771 _error_handler(conn, DBI_ERROR_BADPTR);
772 return 0;
773 }
774
775 newlen = conn->driver->functions->quote_binary(conn, orig, from_length, &temp);
776 if (!newlen) {
777 _error_handler(conn, DBI_ERROR_NOMEM);
778 return 0;
779 }
780
781 *ptr_dest = temp;
782
783 return newlen;
784 }
785
786 /* CONN: escaping functions. These functions escape SQL special
787 characters but do not add the quotes like the quoting functions
788 do */
789
dbi_conn_escape_string_copy(dbi_conn Conn,const char * orig,char ** newquoted)790 size_t dbi_conn_escape_string_copy(dbi_conn Conn, const char *orig, char **newquoted) {
791 size_t newlen;
792
793 if (!Conn) {
794 return 0;
795 }
796
797 newlen = dbi_conn_quote_string_copy(Conn, orig, newquoted);
798
799 if (newlen) {
800 (*newquoted)[newlen-1] = '\0';
801 memmove(*newquoted, (*newquoted)+1, newlen-1);
802 }
803
804 return newlen-2;
805 }
806
dbi_conn_escape_string(dbi_conn Conn,char ** orig)807 size_t dbi_conn_escape_string(dbi_conn Conn, char **orig) {
808 size_t newlen;
809
810 newlen = dbi_conn_quote_string(Conn, orig);
811
812 if (newlen) {
813 (*orig)[newlen-1] = '\0';
814 memmove(*orig, (*orig)+1, newlen-1);
815 }
816 return newlen-2;
817 }
818
dbi_conn_escape_binary_copy(dbi_conn Conn,const unsigned char * orig,size_t from_length,unsigned char ** ptr_dest)819 size_t dbi_conn_escape_binary_copy(dbi_conn Conn, const unsigned char *orig, size_t from_length, unsigned char **ptr_dest) {
820 size_t newlen;
821
822 newlen = dbi_conn_quote_binary_copy(Conn, orig, from_length, ptr_dest);
823
824 if (newlen) {
825 (*ptr_dest)[newlen-1] = '\0';
826 memmove(*ptr_dest, (*ptr_dest)+1, newlen-1);
827 }
828
829 return newlen-2;
830 }
831
832 /* CONN: option manipulation */
833
dbi_conn_set_option(dbi_conn Conn,const char * key,const char * value)834 int dbi_conn_set_option(dbi_conn Conn, const char *key, const char *value) {
835 dbi_conn_t *conn = Conn;
836 dbi_option_t *option;
837
838 if (!conn) {
839 return -1;
840 }
841
842 _reset_conn_error(conn);
843
844 option = _find_or_create_option_node(conn, key);
845 if (!option) {
846 _error_handler(conn, DBI_ERROR_NOMEM);
847 return -1;
848 }
849
850 if (option->string_value) free(option->string_value);
851 option->string_value = (value) ? strdup(value) : NULL;
852 option->numeric_value = 0;
853
854 return 0;
855 }
856
dbi_conn_set_option_numeric(dbi_conn Conn,const char * key,int value)857 int dbi_conn_set_option_numeric(dbi_conn Conn, const char *key, int value) {
858 dbi_conn_t *conn = Conn;
859 dbi_option_t *option;
860
861 if (!conn) {
862 return -1;
863 }
864
865 _reset_conn_error(conn);
866
867 option = _find_or_create_option_node(conn, key);
868 if (!option) {
869 _error_handler(conn, DBI_ERROR_NOMEM);
870 return -1;
871 }
872
873 if (option->string_value) free(option->string_value);
874 option->string_value = NULL;
875 option->numeric_value = value;
876
877 return 0;
878 }
879
_get_option(dbi_conn Conn,const char * key,int aggressive)880 static const char *_get_option(dbi_conn Conn, const char *key, int aggressive) {
881 dbi_conn_t *conn = Conn;
882 dbi_option_t *option;
883
884 if (!conn) {
885 return NULL;
886 }
887
888 _reset_conn_error(conn);
889
890 option = conn->options;
891 while (option && strcasecmp(key, option->key)) {
892 option = option->next;
893 }
894
895 if (option) {
896 return option->string_value;
897 }
898 else {
899 if (aggressive) _error_handler(conn, DBI_ERROR_BADNAME);
900 return NULL;
901 }
902 }
903
dbi_conn_get_option(dbi_conn Conn,const char * key)904 const char *dbi_conn_get_option(dbi_conn Conn, const char *key) {
905 return _get_option(Conn, key, 0);
906 }
907
dbi_conn_require_option(dbi_conn Conn,const char * key)908 const char *dbi_conn_require_option(dbi_conn Conn, const char *key) {
909 return _get_option(Conn, key, 1);
910 }
911
_get_option_numeric(dbi_conn Conn,const char * key,int aggressive)912 static int _get_option_numeric(dbi_conn Conn, const char *key, int aggressive) {
913 dbi_conn_t *conn = Conn;
914 dbi_option_t *option;
915
916 if (!conn) return 0;
917
918 _reset_conn_error(conn);
919
920 option = conn->options;
921 while (option && strcasecmp(key, option->key)) {
922 option = option->next;
923 }
924
925 if (option) {
926 return option->numeric_value;
927 }
928 else {
929 if (aggressive) _error_handler(conn, DBI_ERROR_BADNAME);
930 return 0;
931 }
932 }
933
dbi_conn_get_option_numeric(dbi_conn Conn,const char * key)934 int dbi_conn_get_option_numeric(dbi_conn Conn, const char *key) {
935 return _get_option_numeric(Conn, key, 0);
936 }
937
dbi_conn_require_option_numeric(dbi_conn Conn,const char * key)938 int dbi_conn_require_option_numeric(dbi_conn Conn, const char *key) {
939 return _get_option_numeric(Conn, key, 1);
940 }
941
dbi_conn_get_option_list(dbi_conn Conn,const char * current)942 const char *dbi_conn_get_option_list(dbi_conn Conn, const char *current) {
943 dbi_conn_t *conn = Conn;
944 dbi_option_t *option;
945
946 if (!conn) {
947 return NULL;
948 }
949
950 _reset_conn_error(conn);
951
952 if (!conn->options) {
953 _error_handler(conn, DBI_ERROR_BADPTR);
954 return NULL;
955 }
956 option = conn->options;
957
958 if (!current) {
959 return option->key;
960 }
961 else {
962 while (option && strcasecmp(current, option->key)) {
963 option = option->next;
964 }
965 /* return NULL if there are no more options but don't make
966 this an error */
967 return (option && option->next) ? option->next->key : NULL;
968 }
969 }
970
dbi_conn_clear_option(dbi_conn Conn,const char * key)971 void dbi_conn_clear_option(dbi_conn Conn, const char *key) {
972 dbi_conn_t *conn = Conn;
973 dbi_option_t *prevoption = NULL; /* shut up compiler */
974 dbi_option_t *option;
975
976 if (!conn) return;
977 option = conn->options;
978
979 while (option && strcasecmp(key, option->key)) {
980 prevoption = option;
981 option = option->next;
982 }
983 if (!option) return;
984 if (option == conn->options) {
985 conn->options = option->next;
986 }
987 else {
988 prevoption->next = option->next;
989 }
990 free(option->key);
991 free(option->string_value);
992 free(option);
993 return;
994 }
995
dbi_conn_clear_options(dbi_conn Conn)996 void dbi_conn_clear_options(dbi_conn Conn) {
997 dbi_conn_t *conn = Conn;
998 dbi_option_t *cur;
999 dbi_option_t *next;
1000
1001 if (!conn) return;
1002 cur = conn->options;
1003
1004 while (cur) {
1005 next = cur->next;
1006 free(cur->key);
1007 free(cur->string_value);
1008 free(cur);
1009 cur = next;
1010 }
1011
1012 conn->options = NULL;
1013 }
1014
1015 /* DRIVER: SQL layer functions */
1016
dbi_conn_connect(dbi_conn Conn)1017 int dbi_conn_connect(dbi_conn Conn) {
1018 dbi_conn_t *conn = Conn;
1019 int retval;
1020
1021 if (!conn) return -1;
1022
1023 _reset_conn_error(conn);
1024
1025 retval = conn->driver->functions->connect(conn);
1026 if (retval == -1) {
1027 /* couldn't create a connection and no DBD-level error information is available */
1028 _error_handler(conn, DBI_ERROR_NOCONN);
1029 }
1030 /* else if (retval == -2) { */
1031 /* a DBD-level error has already been set and the callback has already triggered */
1032 /* } */
1033
1034 return retval;
1035 }
1036
dbi_conn_get_socket(dbi_conn Conn)1037 int dbi_conn_get_socket(dbi_conn Conn){
1038 dbi_conn_t *conn = Conn;
1039 int retval;
1040
1041 if (!conn || !(conn->connection)) {
1042 return -1;
1043 }
1044
1045 _reset_conn_error(conn);
1046
1047 retval = conn->driver->functions->get_socket(conn);
1048
1049 return retval;
1050 }
1051
dbi_conn_get_encoding(dbi_conn Conn)1052 const char *dbi_conn_get_encoding(dbi_conn Conn){
1053 dbi_conn_t *conn = Conn;
1054 const char *retval;
1055
1056 if (!conn || !(conn->connection)) return NULL;
1057
1058 _reset_conn_error(conn);
1059
1060 retval = conn->driver->functions->get_encoding(conn);
1061
1062 return retval;
1063 }
1064
dbi_conn_get_engine_version(dbi_conn Conn)1065 unsigned int dbi_conn_get_engine_version(dbi_conn Conn){
1066 dbi_conn_t *conn = Conn;
1067 char versionstring[VERSIONSTRING_LENGTH];
1068
1069 if (!conn || !(conn->connection)) return 0;
1070
1071 _reset_conn_error(conn);
1072
1073 conn->driver->functions->get_engine_version(conn, versionstring);
1074
1075 return _parse_versioninfo(versionstring);
1076 }
1077
dbi_conn_get_engine_version_string(dbi_conn Conn,char * versionstring)1078 char* dbi_conn_get_engine_version_string(dbi_conn Conn, char *versionstring) {
1079 dbi_conn_t *conn = Conn;
1080
1081 if (!conn || !(conn->connection)) return 0;
1082
1083 _reset_conn_error(conn);
1084
1085 return conn->driver->functions->get_engine_version(conn, versionstring);
1086 }
1087
dbi_conn_get_db_list(dbi_conn Conn,const char * pattern)1088 dbi_result dbi_conn_get_db_list(dbi_conn Conn, const char *pattern) {
1089 dbi_conn_t *conn = Conn;
1090 dbi_result_t *result;
1091
1092 if (!conn || !(conn->connection)) return NULL;
1093
1094 _reset_conn_error(conn);
1095
1096 result = conn->driver->functions->list_dbs(conn, pattern);
1097
1098 if (result == NULL) {
1099 _error_handler(conn, DBI_ERROR_DBD);
1100 }
1101
1102 return (dbi_result)result;
1103 }
1104
dbi_conn_get_table_list(dbi_conn Conn,const char * db,const char * pattern)1105 dbi_result dbi_conn_get_table_list(dbi_conn Conn, const char *db, const char *pattern) {
1106 dbi_conn_t *conn = Conn;
1107 dbi_result_t *result;
1108
1109 if (!conn || !(conn->connection)) return NULL;
1110
1111 _reset_conn_error(conn);
1112
1113 result = conn->driver->functions->list_tables(conn, db, pattern);
1114
1115 if (result == NULL) {
1116 _error_handler(conn, DBI_ERROR_DBD);
1117 }
1118
1119 return (dbi_result)result;
1120 }
1121
dbi_conn_query(dbi_conn Conn,const char * statement)1122 dbi_result dbi_conn_query(dbi_conn Conn, const char *statement) {
1123 dbi_conn_t *conn = Conn;
1124 dbi_result_t *result;
1125
1126 if (!conn || !(conn->connection)) return NULL;
1127
1128 _reset_conn_error(conn);
1129
1130 _logquery(conn, "[query] %s\n", statement);
1131 result = conn->driver->functions->query(conn, statement);
1132
1133 if (result == NULL) {
1134 _error_handler(conn, DBI_ERROR_DBD);
1135 }
1136
1137 return (dbi_result)result;
1138 }
1139
dbi_conn_queryf(dbi_conn Conn,const char * formatstr,...)1140 dbi_result dbi_conn_queryf(dbi_conn Conn, const char *formatstr, ...) {
1141 dbi_conn_t *conn = Conn;
1142 char *statement;
1143 dbi_result_t *result;
1144 va_list ap;
1145
1146 if (!conn || !(conn->connection)) return NULL;
1147
1148 _reset_conn_error(conn);
1149
1150 va_start(ap, formatstr);
1151 vasprintf(&statement, formatstr, ap);
1152 va_end(ap);
1153
1154 _logquery(conn, "[queryf] %s\n", statement);
1155 result = conn->driver->functions->query(conn, statement);
1156
1157 if (result == NULL) {
1158 _error_handler(conn, DBI_ERROR_DBD);
1159 }
1160 free(statement);
1161
1162 return (dbi_result)result;
1163 }
1164
dbi_conn_query_null(dbi_conn Conn,const unsigned char * statement,size_t st_length)1165 dbi_result dbi_conn_query_null(dbi_conn Conn, const unsigned char *statement, size_t st_length) {
1166 dbi_conn_t *conn = Conn;
1167 dbi_result_t *result;
1168
1169 if (!conn || !(conn->connection)) return NULL;
1170
1171 _reset_conn_error(conn);
1172
1173 _logquery_null(conn, (const char *)statement, st_length);
1174 result = conn->driver->functions->query_null(conn, statement, st_length);
1175
1176 if (result == NULL) {
1177 _error_handler(conn, DBI_ERROR_DBD);
1178 }
1179
1180 return (dbi_result)result;
1181 }
1182
dbi_conn_select_db(dbi_conn Conn,const char * db)1183 int dbi_conn_select_db(dbi_conn Conn, const char *db) {
1184 dbi_conn_t *conn = Conn;
1185 const char *retval;
1186
1187 if (!conn || !(conn->connection)) return -1;
1188
1189 _reset_conn_error(conn);
1190
1191 if (conn->current_db) free(conn->current_db);
1192 conn->current_db = NULL;
1193
1194 retval = conn->driver->functions->select_db(conn, db);
1195
1196 if (retval == NULL) {
1197 _error_handler(conn, DBI_ERROR_DBD);
1198 return -1;
1199 }
1200
1201 if (*retval == '\0') {
1202 /* if "" was returned, conn doesn't support switching databases */
1203 _error_handler(conn, DBI_ERROR_UNSUPPORTED);
1204 return -1;
1205 }
1206 else {
1207 conn->current_db = strdup(retval);
1208 }
1209
1210 return 0;
1211 }
1212
dbi_conn_sequence_last(dbi_conn Conn,const char * name)1213 unsigned long long dbi_conn_sequence_last(dbi_conn Conn, const char *name) {
1214 dbi_conn_t *conn = Conn;
1215 unsigned long long result;
1216 if (!conn || !(conn->connection)) return 0;
1217
1218 _reset_conn_error(conn);
1219
1220 result = conn->driver->functions->get_seq_last(conn, name);
1221 return result;
1222 }
1223
dbi_conn_sequence_next(dbi_conn Conn,const char * name)1224 unsigned long long dbi_conn_sequence_next(dbi_conn Conn, const char *name) {
1225 dbi_conn_t *conn = Conn;
1226 unsigned long long result;
1227 if (!conn || !(conn->connection)) return 0;
1228
1229 _reset_conn_error(conn);
1230
1231 result = conn->driver->functions->get_seq_next(conn, name);
1232 return result;
1233 }
1234
dbi_conn_ping(dbi_conn Conn)1235 int dbi_conn_ping(dbi_conn Conn) {
1236 dbi_conn_t *conn = Conn;
1237 int result;
1238
1239 if (!conn || !(conn->connection)) return 0;
1240
1241 _reset_conn_error(conn);
1242
1243 result = conn->driver->functions->ping(conn);
1244 return result;
1245 }
1246
1247 /* XXX TRANSACTION RELATED FUNCTIONS XXX */
dbi_conn_transaction_begin(dbi_conn Conn)1248 int dbi_conn_transaction_begin(dbi_conn Conn) {
1249 dbi_conn_t *conn = Conn;
1250 int result;
1251
1252 if (!conn || !(conn->connection)) return 0;
1253
1254 _reset_conn_error(conn);
1255
1256 result = conn->driver->functions->transaction_begin(conn);
1257 return result;
1258 }
1259
dbi_conn_transaction_commit(dbi_conn Conn)1260 int dbi_conn_transaction_commit(dbi_conn Conn) {
1261 dbi_conn_t *conn = Conn;
1262 int result;
1263
1264 if (!conn || !(conn->connection)) return 0;
1265
1266 _reset_conn_error(conn);
1267
1268 result = conn->driver->functions->transaction_commit(conn);
1269 return result;
1270 }
1271
dbi_conn_transaction_rollback(dbi_conn Conn)1272 int dbi_conn_transaction_rollback(dbi_conn Conn) {
1273 dbi_conn_t *conn = Conn;
1274 int result;
1275
1276 if (!conn || !(conn->connection)) return 0;
1277
1278 _reset_conn_error(conn);
1279
1280 result = conn->driver->functions->transaction_rollback(conn);
1281 return result;
1282 }
1283
dbi_conn_savepoint(dbi_conn Conn,const char * savepoint)1284 int dbi_conn_savepoint(dbi_conn Conn, const char *savepoint) {
1285 dbi_conn_t *conn = Conn;
1286 int result;
1287
1288 if (!conn || !(conn->connection)
1289 || !savepoint) return 0;
1290
1291 _reset_conn_error(conn);
1292
1293 result = conn->driver->functions->savepoint(conn, savepoint);
1294 return result;
1295 }
1296
dbi_conn_rollback_to_savepoint(dbi_conn Conn,const char * savepoint)1297 int dbi_conn_rollback_to_savepoint(dbi_conn Conn, const char *savepoint) {
1298 dbi_conn_t *conn = Conn;
1299 int result;
1300
1301 if (!conn || !(conn->connection)
1302 || !savepoint) return 0;
1303
1304 _reset_conn_error(conn);
1305
1306 result = conn->driver->functions->rollback_to_savepoint(conn, savepoint);
1307 return result;
1308 }
1309
dbi_conn_release_savepoint(dbi_conn Conn,const char * savepoint)1310 int dbi_conn_release_savepoint(dbi_conn Conn, const char *savepoint) {
1311 dbi_conn_t *conn = Conn;
1312 int result;
1313
1314 if (!conn || !(conn->connection)
1315 || !savepoint) return 0;
1316
1317 _reset_conn_error(conn);
1318
1319 result = conn->driver->functions->release_savepoint(conn, savepoint);
1320 return result;
1321 }
1322
1323
1324 /* XXX INTERNAL PRIVATE IMPLEMENTATION FUNCTIONS XXX */
1325
_get_driver(const char * filename,dbi_inst_t * inst)1326 static dbi_driver_t *_get_driver(const char *filename, dbi_inst_t *inst) {
1327 dbi_driver_t *driver;
1328 void *dlhandle;
1329 void *symhandle;
1330 const char **custom_functions_list;
1331 unsigned int idx = 0;
1332 dbi_custom_function_t *prevcustom = NULL;
1333 dbi_custom_function_t *custom = NULL;
1334 const char* error;
1335
1336 dlhandle = my_dlopen(filename, DLOPEN_FLAG); /* DLOPEN_FLAG defined by autoconf */
1337
1338 if (dlhandle == NULL) {
1339 fprintf(stderr, "%s\n", my_dlerror());
1340 return NULL;
1341 }
1342 else {
1343 driver = malloc(sizeof(dbi_driver_t));
1344 if (!driver) return NULL;
1345
1346 driver->dlhandle = dlhandle;
1347 driver->filename = strdup(filename);
1348 driver->dbi_inst = inst;
1349 driver->next = NULL;
1350 driver->caps = NULL;
1351 driver->functions = malloc(sizeof(dbi_functions_t));
1352
1353 if ( /* nasty looking if block... is there a better way to do it? */
1354 ((driver->functions->register_driver = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_register_driver")) == NULL) ||
1355 ((driver->functions->initialize = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_initialize")) == NULL) ||
1356 ((driver->functions->finalize = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_finalize")) == NULL) ||
1357 ((driver->functions->connect = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_connect")) == NULL) ||
1358 ((driver->functions->disconnect = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_disconnect")) == NULL) ||
1359 ((driver->functions->fetch_row = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_fetch_row")) == NULL) ||
1360 ((driver->functions->free_query = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_free_query")) == NULL) ||
1361 ((driver->functions->goto_row = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_goto_row")) == NULL) ||
1362 ((driver->functions->get_socket = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_get_socket")) == NULL) ||
1363 ((driver->functions->get_encoding = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_get_encoding")) == NULL) ||
1364 ((driver->functions->encoding_from_iana = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_encoding_from_iana")) == NULL) ||
1365 ((driver->functions->encoding_to_iana = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_encoding_to_iana")) == NULL) ||
1366 ((driver->functions->get_engine_version = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_get_engine_version")) == NULL) ||
1367 ((driver->functions->list_dbs = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_list_dbs")) == NULL) ||
1368 ((driver->functions->list_tables = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_list_tables")) == NULL) ||
1369 ((driver->functions->query = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_query")) == NULL) ||
1370 ((driver->functions->query_null = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_query_null")) == NULL) ||
1371 ((driver->functions->transaction_begin = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_transaction_begin")) == NULL) ||
1372 ((driver->functions->transaction_commit = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_transaction_commit")) == NULL) ||
1373 ((driver->functions->transaction_rollback = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_transaction_rollback")) == NULL) ||
1374 ((driver->functions->savepoint = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_savepoint")) == NULL) ||
1375 ((driver->functions->rollback_to_savepoint = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_rollback_to_savepoint")) == NULL) ||
1376 ((driver->functions->release_savepoint = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_release_savepoint")) == NULL) ||
1377 ((driver->functions->quote_string = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_quote_string")) == NULL) ||
1378 ((driver->functions->quote_binary = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_quote_binary")) == NULL) ||
1379 ((driver->functions->conn_quote_string = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_conn_quote_string")) == NULL) ||
1380 ((driver->functions->select_db = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_select_db")) == NULL) ||
1381 ((driver->functions->geterror = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_geterror")) == NULL) ||
1382 ((driver->functions->get_seq_last = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_get_seq_last")) == NULL) ||
1383 ((driver->functions->get_seq_next = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_get_seq_next")) == NULL) ||
1384 ((driver->functions->ping = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_ping")) == NULL)
1385 )
1386 {
1387 free(driver->functions);
1388 free(driver->filename);
1389 free(driver);
1390 return NULL;
1391 }
1392 driver->functions->register_driver(&driver->info, &custom_functions_list, &driver->reserved_words);
1393 driver->custom_functions = NULL; /* in case no custom functions are available */
1394
1395 /* this is a weird hack for the sake of dlsym
1396 portability. I can't imagine why using dlhandle
1397 fails on FreeBSD except that dlsym may expect a
1398 leading underscore in front of the function
1399 names. But then, why does RTLD_NEXT work? */
1400 /* update 2008-11-28: this is most likely a FreeBSD
1401 bug which was fixed in 6.3. TODO: follow up on this
1402 once I have a 6.3 or later box */
1403 if (DLSYM_HANDLE) { /* most OSes */
1404 symhandle = dlhandle;
1405 }
1406 else { /* the BSDs */
1407 symhandle = RTLD_NEXT;
1408 }
1409
1410 while (custom_functions_list && custom_functions_list[idx] != NULL) {
1411 custom = malloc(sizeof(dbi_custom_function_t));
1412 if (!custom) {
1413 _free_custom_functions(driver);
1414 free(driver->functions);
1415 free(driver->filename);
1416 free(driver);
1417 return NULL;
1418 }
1419 custom->next = NULL;
1420 custom->name = custom_functions_list[idx];
1421 /* snprintf(function_name, 256, DLSYM_PREFIX "dbd_%s", custom->name); */
1422 /* printf("loading %s<<\n", custom->name); */
1423 my_dlerror(); /* clear any previous errors */
1424 custom->function_pointer = my_dlsym(symhandle, custom->name);
1425 /* if (!custom->function_pointer) { */
1426 if ((error = my_dlerror()) != NULL) {
1427 /* fprintf(STDERR, error); */
1428
1429 /* this usually fails because a function was
1430 renamed, is no longer available, or not
1431 yet available. Simply skip this
1432 function */
1433 free(custom); /* not linked into the list yet */
1434 idx++;
1435 continue;
1436 }
1437 if (driver->custom_functions == NULL) {
1438 driver->custom_functions = custom;
1439 }
1440 else {
1441 prevcustom->next = custom;
1442 }
1443 prevcustom = custom;
1444 idx++;
1445 }
1446 }
1447 return driver;
1448 }
1449
_free_custom_functions(dbi_driver_t * driver)1450 static void _free_custom_functions(dbi_driver_t *driver) {
1451 dbi_custom_function_t *cur;
1452 dbi_custom_function_t *next;
1453
1454 if (!driver) return;
1455 cur = driver->custom_functions;
1456
1457 while (cur) {
1458 next = cur->next;
1459 free(cur);
1460 cur = next;
1461 }
1462
1463 driver->custom_functions = NULL;
1464 }
1465
_free_caps(_capability_t * caproot)1466 static void _free_caps(_capability_t *caproot) {
1467 _capability_t *cap = caproot;
1468 while (cap) {
1469 _capability_t *nextcap = cap->next;
1470 if (cap->name) free(cap->name);
1471 free(cap);
1472 cap = nextcap;
1473 }
1474 return;
1475 }
1476
_update_internal_conn_list(dbi_conn_t * conn,const int operation)1477 static int _update_internal_conn_list(dbi_conn_t *conn, const int operation) {
1478 /* maintain internal linked list of conns so that we can unload them all
1479 * when dbi is shutdown
1480 *
1481 * operation = -1: remove conn
1482 * = 0: just look for conn (return 1 if found, -1 if not)
1483 * = 1: add conn */
1484 dbi_conn_t *curconn = conn->driver->dbi_inst->rootconn;
1485 dbi_conn_t *prevconn = NULL;
1486
1487 if ((operation == -1) || (operation == 0)) {
1488 while (curconn && (curconn != conn)) {
1489 prevconn = curconn;
1490 curconn = curconn->next;
1491 }
1492 if (!curconn) return -1;
1493 if (operation == 0) return 1;
1494 else if (operation == -1) {
1495 if (prevconn) prevconn->next = curconn->next;
1496 else conn->driver->dbi_inst->rootconn = NULL;
1497 return 0;
1498 }
1499 }
1500 else if (operation == 1) {
1501 while (curconn && curconn->next) {
1502 curconn = curconn->next;
1503 }
1504 if (curconn) {
1505 curconn->next = conn;
1506 }
1507 else {
1508 conn->driver->dbi_inst->rootconn = conn;
1509 }
1510 conn->next = NULL;
1511 return 0;
1512 }
1513 return -1;
1514 }
1515
_find_or_create_option_node(dbi_conn Conn,const char * key)1516 static dbi_option_t *_find_or_create_option_node(dbi_conn Conn, const char *key) {
1517 dbi_option_t *prevoption = NULL;
1518 dbi_conn_t *conn = Conn;
1519 dbi_option_t *option = conn->options;
1520
1521 while (option && strcasecmp(key, option->key)) {
1522 prevoption = option;
1523 option = option->next;
1524 }
1525
1526 if (option == NULL) {
1527 /* allocate a new option node */
1528 option = malloc(sizeof(dbi_option_t));
1529 if (!option) return NULL;
1530 option->next = NULL;
1531 option->key = strdup(key);
1532 option->string_value = NULL;
1533 if (conn->options == NULL) {
1534 conn->options = option;
1535 }
1536 else {
1537 prevoption->next = option;
1538 }
1539 }
1540
1541 return option;
1542 }
1543
1544 #define COUNTOF(array) (sizeof(array)/sizeof((array)[0]))
1545
1546 /* sets conn->error_number and conn->error_message values */
_error_handler(dbi_conn_t * conn,dbi_error_flag errflag)1547 void _error_handler(dbi_conn_t *conn, dbi_error_flag errflag) {
1548 int my_errno = 0;
1549 char *errmsg = NULL;
1550 int errstatus;
1551 static const char *errflag_messages[] = {
1552 /* DBI_ERROR_USER */ NULL,
1553 /* DBI_ERROR_DBD */ NULL,
1554 /* DBI_ERROR_BADOBJECT */ "An invalid or NULL object was passed to libdbi",
1555 /* DBI_ERROR_BADTYPE */ "The requested variable type does not match what libdbi thinks it should be",
1556 /* DBI_ERROR_BADIDX */ "An invalid or out-of-range index was passed to libdbi",
1557 /* DBI_ERROR_BADNAME */ "An invalid name was passed to libdbi",
1558 /* DBI_ERROR_UNSUPPORTED */ "This particular libdbi driver or connection does not support this feature",
1559 /* DBI_ERROR_NOCONN */ "libdbi could not establish a connection",
1560 /* DBI_ERROR_NOMEM */ "libdbi ran out of memory",
1561 /* DBI_ERROR_BADPTR */ "An invalid pointer was passed to libdbi",
1562 /* DBI_ERROR_NONE */ NULL,
1563 /* DBI_ERROR_CLIENT */ NULL
1564 };
1565
1566 if (conn == NULL) {
1567 /* temp hack... if a result is disjoined and encounters an error, conn
1568 * will be null when we get here. just ignore it, since we assume
1569 * errors require a valid conn. this shouldn't even be a problem now,
1570 * since (currently) the only reason a result would be disjoint is if a
1571 * garbage collector was about to get rid of it. */
1572 // conn will also be NULL if the connection itself could not be created,
1573 // or if a NULL result handle was passed to a dbi routine, so we would
1574 // always want to return if NULL. Probably should say something though:
1575 fprintf(stderr, "libdbi: _error_handler: %s (NULL conn/result handle)\n",
1576 errflag >= DBI_ERROR_BADOBJECT-1 && errflag < COUNTOF(errflag_messages)-1
1577 ? errflag_messages[errflag+1] : "");
1578 return;
1579 }
1580
1581 if (errflag == DBI_ERROR_DBD) {
1582 errstatus = conn->driver->functions->geterror(conn, &my_errno, &errmsg);
1583
1584 if (errstatus == -1) {
1585 /* not _really_ an error. XXX debug this, does it ever actually happen? */
1586 return;
1587 }
1588 }
1589 else {
1590 my_errno = errflag;
1591 }
1592
1593 if (conn->error_message) free(conn->error_message);
1594
1595 if ((errflag-DBI_ERROR_USER) >= 0 && (errflag-DBI_ERROR_USER) < COUNTOF(errflag_messages)
1596 && errflag_messages[(errflag-DBI_ERROR_USER)] != NULL) {
1597 errmsg = strdup(errflag_messages[(errflag-DBI_ERROR_USER)]);
1598 }
1599
1600 conn->error_flag = errflag; /* should always be DBI_ERROR_DBD,
1601 DBI_ERROR_UNSUPPORTED,
1602 DBI_ERROR_NOCONN,
1603 DBI_ERROR_BADNAME, or
1604 DBI_ERROR_NOMEM for conn
1605 errors */
1606 conn->error_number = my_errno;
1607 conn->error_message = errmsg;
1608
1609 if (conn->error_handler != NULL) {
1610 /* trigger the external callback function */
1611 conn->error_handler((dbi_conn)conn, conn->error_handler_argument);
1612 }
1613 }
1614
1615 /* this function should be called by all functions that may alter the
1616 connection error status*/
_reset_conn_error(dbi_conn_t * conn)1617 void _reset_conn_error(dbi_conn_t *conn) {
1618 if (conn) {
1619 conn->error_flag = DBI_ERROR_NONE;
1620 conn->error_number = DBI_ERROR_NONE;
1621 if (conn->error_message) {
1622 free(conn->error_message);
1623 conn->error_message = NULL;
1624 }
1625 }
1626 }
1627
_verbose_handler(dbi_conn_t * conn,const char * fmt,...)1628 void _verbose_handler(dbi_conn_t *conn, const char* fmt, ...) {
1629 va_list ap;
1630
1631 if(conn && dbi_conn_get_option_numeric(conn, "Verbosity"))
1632 {
1633 fputs("libdbi: ",stderr);
1634 va_start(ap, fmt);
1635 vfprintf(stderr, fmt, ap);
1636 va_end(ap);
1637 }
1638 }
1639
_logquery(dbi_conn_t * conn,const char * fmt,...)1640 void _logquery(dbi_conn_t *conn, const char* fmt, ...) {
1641 va_list ap;
1642
1643 if(conn && dbi_conn_get_option_numeric(conn, "LogQueries")){
1644 fputs("libdbi: ", stderr);
1645 va_start(ap, fmt);
1646 vfprintf(stderr, fmt, ap);
1647 va_end(ap);
1648 }
1649 }
1650
_logquery_null(dbi_conn_t * conn,const char * statement,size_t st_length)1651 void _logquery_null(dbi_conn_t *conn, const char* statement, size_t st_length) {
1652 if(conn && dbi_conn_get_option_numeric(conn, "LogQueries")){
1653 fputs("libdbi: [query_null] ", stderr);
1654 fwrite(statement, 1, st_length, stderr);
1655 fputc('\n', stderr);
1656 }
1657 }
1658
_isolate_attrib(unsigned int attribs,unsigned int rangemin,unsigned int rangemax)1659 unsigned int _isolate_attrib(unsigned int attribs, unsigned int rangemin, unsigned int rangemax) {
1660 /* hahaha! who woulda ever thunk strawberry's code would come in handy? */
1661 // find first (highest) bit set; methods not using FP can be found at
1662 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
1663 /* unsigned startbit = log(rangemin)/log(2); */
1664 /* unsigned endbit = log(rangemax)/log(2); */
1665 unsigned int startbit = 0;
1666 unsigned int endbit = 0;
1667
1668 while (rangemin >>= 1) {
1669 startbit++;
1670 }
1671
1672 while (rangemax >>= 1) {
1673 endbit++;
1674 }
1675
1676 // construct mask from startbit to endbit inclusive
1677 unsigned attrib_mask = ((1<<(endbit+1))-1) ^ ((1<<startbit)-1);
1678 return attribs & attrib_mask;
1679 }
1680
1681 /* computes an int from a [[[[A.]B.]C.]D.]E version number according to this
1682 formula: version = E + D*100 + C*10000 + B*1000000 + A*100000000 */
_parse_versioninfo(const char * version)1683 static unsigned int _parse_versioninfo(const char *version) {
1684 char my_version[VERSIONSTRING_LENGTH];
1685 char* start;
1686 char* dot;
1687 int i = 0;
1688 unsigned int n_version = 0;
1689 unsigned int n_multiplier = 1;
1690
1691 if (!version || !*version) {
1692 return 0;
1693 }
1694
1695 /* get a copy of version to mangle */
1696 strncpy(my_version, version, VERSIONSTRING_LENGTH-1);
1697 my_version[VERSIONSTRING_LENGTH-1] = '\0';
1698
1699 /* remove trailing periods */
1700 if (my_version[strlen(my_version)-1] == '.') {
1701 my_version[strlen(my_version)-1] = '\0';
1702 }
1703
1704 start = my_version;
1705 while ((dot = strrchr(start, (int)'.')) != NULL && i<5) {
1706 n_version += atoi(dot+1) * n_multiplier;
1707 *dot = '\0';
1708 n_multiplier *= 100;
1709 i++;
1710 }
1711
1712 /* take care of the remainder */
1713 n_version += atoi(start) * n_multiplier;
1714
1715 if (i==5) {
1716 /* version string can't be encoded in an unsigned int */
1717 return 0;
1718 }
1719 return n_version;
1720 }
1721
1722 /* this is to work around nasty database client libraries which
1723 install exit handlers although they're not supposed to. If we
1724 unload drivers linked against one of these libraries, the
1725 application linked against libdbi will crash on exit if running on
1726 FreeBSD and other OSes sticking to the rule. Drivers which can be
1727 safely dlclose()d should set the driver capability "safe_dlclose"
1728 to nonzero */
1729 /* returns 0 if the driver was closed, 1 if not */
_safe_dlclose(dbi_driver_t * driver)1730 static int _safe_dlclose(dbi_driver_t *driver) {
1731 int may_close = 0;
1732
1733 may_close = dbi_driver_cap_get((dbi_driver)driver, "safe_dlclose");
1734 if (may_close) {
1735 my_dlclose(driver->dlhandle);
1736 return 0;
1737 }
1738 return 1;
1739 }
1740
1741
1742 #if HAVE_MACH_O_DYLD_H
1743 static int dyld_error_set=0;
dyld_dlopen(const char * file)1744 static void * dyld_dlopen(const char * file)
1745 {
1746 NSObjectFileImage o=NULL;
1747 NSObjectFileImageReturnCode r;
1748 NSModule m=NULL;
1749 const unsigned int flags = NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE;
1750 dyld_error_set=0;
1751 r = NSCreateObjectFileImageFromFile(file,&o);
1752 if (NSObjectFileImageSuccess == r)
1753 {
1754 m=NSLinkModule(o,file,flags);
1755 NSDestroyObjectFileImage(o);
1756 if (!m) dyld_error_set=1;
1757 }
1758 return (void*)m;
1759 }
dyld_dlsym(void * hand,const char * name)1760 static void * dyld_dlsym(void * hand, const char * name)
1761 {
1762 NSSymbol sym=NSLookupSymbolInModule((NSModule)hand, name);
1763 void * addr = NULL;
1764 dyld_error_set=0;
1765 if (sym) addr=(void*)NSAddressOfSymbol(sym);
1766 if (!addr) dyld_error_set=1;
1767 return addr;
1768 }
dyld_dlclose(void * hand)1769 static int dyld_dlclose(void * hand)
1770 {
1771 int retVal=0;
1772 dyld_error_set=0;
1773 if (!NSUnLinkModule((NSModule)hand, 0))
1774 {
1775 dyld_error_set=1;
1776 retVal=-1;
1777 }
1778 return retVal;
1779 }
1780
dyld_dlerror()1781 static const char * dyld_dlerror()
1782 {
1783 NSLinkEditErrors ler;
1784 int lerno;
1785 const char *errstr;
1786 const char *file;
1787 NSLinkEditError(&ler, &lerno, &file, &errstr);
1788 if (!dyld_error_set) errstr=NULL;
1789 dyld_error_set=0;
1790 return errstr;
1791 }
1792 #endif /* HAVE_MACH_O_DYLD_H */
1793
1794 #ifdef __MINGW32__
1795 static char win_errstr[512];
1796 static int win_err_set = 0;
win_dlopen(const char * filename,int mode)1797 void *win_dlopen(const char *filename, int mode)
1798 {
1799 HINSTANCE handle;
1800 handle = LoadLibrary(filename);
1801 #ifdef _WIN32
1802 if (! handle) {
1803 sprintf(win_errstr, "Error code 1(%d) while loading library %s", GetLastError(), filename);
1804 win_err_set =1;
1805 return NULL;
1806 }
1807 #else
1808 if ((UINT) handle < 32) {
1809 sprintf(win_errstr, "error code 1(%d) while loading library %s", (UINT) handle, filename);
1810 win_err_set =1;
1811 return NULL;
1812 }
1813 #endif
1814 return (void *) handle;
1815 }
1816
win_dlsym(void * handle1,const char * symname)1817 void *win_dlsym(void *handle1, const char *symname)
1818 {
1819 HMODULE handle = (HMODULE) handle1;
1820 void *symaddr;
1821 symaddr = (void *) GetProcAddress(handle, symname);
1822 if (symaddr == NULL)
1823 {
1824 sprintf(win_errstr, "can not find symbol %s", symname);
1825 win_err_set =2;
1826 }
1827 return symaddr;
1828 }
1829
win_dlclose(void * handle1)1830 int win_dlclose(void *handle1)
1831 {
1832 HMODULE handle = (HMODULE) handle1;
1833 #ifdef _WIN32
1834 if (FreeLibrary(handle))
1835 return 0;
1836 else {
1837 sprintf(win_errstr, "error code 3(%d) while closing library", GetLastError());
1838 win_err_set =3;
1839 return -1;
1840 }
1841 #else
1842 FreeLibrary(handle);
1843 return 0;
1844 #endif
1845 }
1846
win_dlerror()1847 char *win_dlerror()
1848 {
1849 return win_errstr;
1850 }
1851
1852 #endif
1853