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