17
17
* License along with this library; if not, write to the Free Software
18
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
* $Id: dbi_main.c,v 1.79 2008/02/06 16:21:29 mhoenicka Exp $
20
* $Id: dbi_main.c,v 1.103 2013/01/24 22:10:18 mhoenicka Exp $
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 /**/
23
27
#ifdef HAVE_CONFIG_H
24
28
#include <config.h>
27
#define _GNU_SOURCE /* since we need the asprintf() prototype */
31
/* #define _GNU_SOURCE */ /* we need the asprintf() prototype but _GNU_SOURCE should be defined in config.h */
30
34
#include <stdlib.h>
31
35
#include <stdarg.h>
32
36
#include <string.h>
37
#include <strings.h> /* for strcasecmp */
38
#include <sys/types.h>
103
112
#define DLSYM_PREFIX ""
116
#define RTLD_NEXT ((void *) -1) /* taken from FreeBSD, just a compile helper */
106
119
/* declarations of optional external functions */
107
#ifndef HAVE_VASPRINTF
108
int int_vasprintf(char **result, const char *format, va_list *args);
120
#if !HAVE_DECL_VASPRINTF
109
121
int vasprintf(char **result, const char *format, va_list args);
111
#ifndef HAVE_ASPRINTF
123
#if !HAVE_DECL_ASPRINTF
112
124
int asprintf(char **result, const char *format, ...);
115
127
/* declarations for internal functions -- anything declared as static won't be accessible by name from client programs */
116
static dbi_driver_t *_get_driver(const char *filename);
128
static dbi_driver_t *_get_driver(const char *filename, dbi_inst_t *inst);
117
129
static void _free_custom_functions(dbi_driver_t *driver);
118
130
static dbi_option_t *_find_or_create_option_node(dbi_conn Conn, const char *key);
119
131
static int _update_internal_conn_list(dbi_conn_t *conn, int operation);
132
144
/* must not be called "ERROR" due to a name clash on Windoze */
133
145
static const char *my_ERROR = "ERROR";
134
static dbi_driver_t *rootdriver;
135
static dbi_conn_t *rootconn;
136
int dbi_verbosity = 1;
146
static dbi_inst dbi_inst_legacy;
138
149
/* XXX DBI CORE FUNCTIONS XXX */
140
int dbi_initialize(const char *driverdir) {
151
int dbi_initialize_r(const char *driverdir, dbi_inst *pInst) {
142
154
struct dirent *driver_dirent = NULL;
143
155
struct stat statbuf;
145
157
char *effective_driverdir;
147
159
int num_loaded = 0;
160
*pInst = NULL; /* use a defined value if the function fails */
148
161
dbi_driver_t *driver = NULL;
149
162
dbi_driver_t *prevdriver = NULL;
151
164
(void)lt_dlinit();
166
/* init the instance */
167
inst = malloc(sizeof(dbi_inst_t));
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 */
154
176
effective_driverdir = (driverdir ? (char *)driverdir : DBI_DRIVER_DIR);
155
177
dir = opendir(effective_driverdir);
161
while ((driver_dirent = readdir(dir)) != NULL) {
183
struct dirent *buffer;
187
/* allocate memory for readdir_r(3) */
188
buffer_size = _dirent_buf_size(dir);
189
if (buffer_size == 0) {
193
buffer = (struct dirent *) malloc (buffer_size);
194
if (buffer == NULL) {
198
memset (buffer, 0, buffer_size);
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) {
163
209
snprintf(fullpath, FILENAME_MAX, "%s%s%s", effective_driverdir, DBI_PATH_SEPARATOR, driver_dirent->d_name);
164
210
if ((stat(fullpath, &statbuf) == 0) && S_ISREG(statbuf.st_mode) && strrchr(driver_dirent->d_name, '.') && (!strcmp(strrchr(driver_dirent->d_name, '.'), DRIVER_EXT))) {
165
211
/* file is a stat'able regular file that ends in .so (or appropriate dynamic library extension) */
166
driver = _get_driver(fullpath);
212
driver = _get_driver(fullpath, inst);
167
213
if (driver && (driver->functions->initialize(driver) != -1)) {
214
if (!inst->rootdriver) {
215
inst->rootdriver = driver;
171
217
if (prevdriver) {
172
218
prevdriver->next = driver;
179
225
if (driver && driver->functions) free(driver->functions);
180
226
if (driver) free(driver);
181
227
driver = NULL; /* don't include in linked list */
182
if (dbi_verbosity) fprintf(stderr, "libdbi: Failed to load driver: %s\n", fullpath);
228
if (inst->dbi_verbosity) fprintf(stderr, "libdbi: Failed to load driver: %s\n", fullpath);
189
236
return num_loaded;
192
void dbi_shutdown() {
193
dbi_conn_t *curconn = rootconn;
239
int dbi_initialize(const char *driverdir) {
240
return (dbi_initialize_r(driverdir, &dbi_inst_legacy));
243
void dbi_shutdown_r(dbi_inst Inst) {
244
dbi_inst_t *inst = (dbi_inst_t*) Inst;
245
dbi_conn_t *curconn = inst->rootconn;
194
246
dbi_conn_t *nextconn;
196
dbi_driver_t *curdriver = rootdriver;
248
dbi_driver_t *curdriver = inst->rootdriver;
197
249
dbi_driver_t *nextdriver;
199
251
while (curconn) {
205
257
while (curdriver) {
206
258
nextdriver = curdriver->next;
259
curdriver->functions->finalize(curdriver);
207
260
_safe_dlclose(curdriver);
208
261
free(curdriver->functions);
209
262
_free_custom_functions(curdriver);
216
269
(void)lt_dlexit();
274
void dbi_shutdown() {
275
dbi_shutdown_r(dbi_inst_legacy);
221
278
const char *dbi_version() {
222
279
return "libdbi v" VERSION;
225
int dbi_set_verbosity(int verbosity) {
282
unsigned int dbi_version_numeric() {
283
return (unsigned int)LIBDBI_VERSION;
286
int dbi_set_verbosity_r(int verbosity, dbi_inst Inst) {
287
dbi_inst_t *inst = (dbi_inst_t*) Inst;
226
288
/* whether or not to spew stderr messages when something bad happens (and
227
289
* isn't handled through the normal connection-oriented DBI error
230
int prev = dbi_verbosity;
231
dbi_verbosity = verbosity;
292
int prev = inst->dbi_verbosity;
293
inst->dbi_verbosity = verbosity;
296
int dbi_set_verbosity(int verbosity) {
297
return dbi_set_verbosity_r(verbosity, dbi_inst_legacy);
235
300
/* XXX DRIVER FUNCTIONS XXX */
237
dbi_driver dbi_driver_list(dbi_driver Current) {
302
dbi_driver dbi_driver_list_r(dbi_driver Current, dbi_inst Inst) {
303
dbi_inst_t *inst = (dbi_inst_t*) Inst;
238
304
dbi_driver_t *current = Current;
240
306
if (current == NULL) {
241
return (dbi_driver)rootdriver;
307
return (dbi_driver)inst->rootdriver;
244
310
return (dbi_driver)current->next;
312
dbi_driver dbi_driver_list(dbi_driver Current) {
313
return dbi_driver_list_r(Current, dbi_inst_legacy);
247
dbi_driver dbi_driver_open(const char *name) {
248
dbi_driver_t *driver = rootdriver;
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;
250
320
while (driver && strcasecmp(name, driver->info->name)) {
251
321
driver = driver->next;
326
dbi_driver dbi_driver_open(const char *name) {
327
return dbi_driver_open_r(name, dbi_inst_legacy);
330
dbi_inst dbi_driver_get_instance(dbi_driver Driver) {
331
dbi_driver_t *driver = Driver;
333
if (!driver) return NULL;
335
return driver->dbi_inst;
257
338
int dbi_driver_is_reserved_word(dbi_driver Driver, const char *word) {
258
339
unsigned int idx = 0;
446
527
/* XXX DRIVER FUNCTIONS XXX */
448
dbi_conn dbi_conn_new(const char *name) {
529
dbi_conn dbi_conn_new_r(const char *name, dbi_inst Inst) {
449
530
dbi_driver driver;
452
driver = dbi_driver_open(name);
533
driver = dbi_driver_open_r(name, Inst);
453
534
conn = dbi_conn_open(driver);
538
dbi_conn dbi_conn_new(const char *name) {
539
return (dbi_conn_new_r(name, dbi_inst_legacy));
458
542
dbi_conn dbi_conn_open(dbi_driver Driver) {
459
543
dbi_driver_t *driver = Driver;
475
559
conn->error_flag = DBI_ERROR_NONE; /* for legacy code only */
476
560
conn->error_number = DBI_ERROR_NONE;
477
561
conn->error_message = NULL;
562
conn->full_errmsg = NULL;
478
563
conn->error_handler = NULL;
479
564
conn->error_handler_argument = NULL;
480
565
_update_internal_conn_list(conn, 1);
536
622
int dbi_conn_error(dbi_conn Conn, const char **errmsg_dest) {
537
623
dbi_conn_t *conn = Conn;
538
624
char number_portion[20];
539
static char *errmsg = NULL; // XXX quick hack, revisit this when API is redesigned
541
626
if (errmsg_dest) {
542
if (errmsg) free(errmsg);
627
if (conn->full_errmsg) free(conn->full_errmsg);
544
629
if (conn->error_number) {
545
630
snprintf(number_portion, 20, "%d: ", conn->error_number);
548
633
number_portion[0] = '\0';
551
asprintf(&errmsg, "%s%s", number_portion, conn->error_message ? conn->error_message : "");
552
*errmsg_dest = errmsg;
636
asprintf(&(conn->full_errmsg), "%s%s", number_portion, conn->error_message ? conn->error_message : "");
637
*errmsg_dest = conn->full_errmsg;
555
640
return conn->error_number;
1082
1166
dbi_conn_t *conn = Conn;
1083
1167
dbi_result_t *result;
1085
if (!conn) return NULL;
1169
if (!conn || !(conn->connection)) return NULL;
1087
1171
_reset_conn_error(conn);
1089
_logquery_null(conn, statement, st_length);
1173
_logquery_null(conn, (const char *)statement, st_length);
1090
1174
result = conn->driver->functions->query_null(conn, statement, st_length);
1092
1176
if (result == NULL) {
1247
/* XXX TRANSACTION RELATED FUNCTIONS XXX */
1248
int dbi_conn_transaction_begin(dbi_conn Conn) {
1249
dbi_conn_t *conn = Conn;
1252
if (!conn || !(conn->connection)) return 0;
1254
_reset_conn_error(conn);
1256
result = conn->driver->functions->transaction_begin(conn);
1260
int dbi_conn_transaction_commit(dbi_conn Conn) {
1261
dbi_conn_t *conn = Conn;
1264
if (!conn || !(conn->connection)) return 0;
1266
_reset_conn_error(conn);
1268
result = conn->driver->functions->transaction_commit(conn);
1272
int dbi_conn_transaction_rollback(dbi_conn Conn) {
1273
dbi_conn_t *conn = Conn;
1276
if (!conn || !(conn->connection)) return 0;
1278
_reset_conn_error(conn);
1280
result = conn->driver->functions->transaction_rollback(conn);
1284
int dbi_conn_savepoint(dbi_conn Conn, const char *savepoint) {
1285
dbi_conn_t *conn = Conn;
1288
if (!conn || !(conn->connection)
1289
|| !savepoint) return 0;
1291
_reset_conn_error(conn);
1293
result = conn->driver->functions->savepoint(conn, savepoint);
1297
int dbi_conn_rollback_to_savepoint(dbi_conn Conn, const char *savepoint) {
1298
dbi_conn_t *conn = Conn;
1301
if (!conn || !(conn->connection)
1302
|| !savepoint) return 0;
1304
_reset_conn_error(conn);
1306
result = conn->driver->functions->rollback_to_savepoint(conn, savepoint);
1310
int dbi_conn_release_savepoint(dbi_conn Conn, const char *savepoint) {
1311
dbi_conn_t *conn = Conn;
1314
if (!conn || !(conn->connection)
1315
|| !savepoint) return 0;
1317
_reset_conn_error(conn);
1319
result = conn->driver->functions->release_savepoint(conn, savepoint);
1163
1324
/* XXX INTERNAL PRIVATE IMPLEMENTATION FUNCTIONS XXX */
1165
static dbi_driver_t *_get_driver(const char *filename) {
1326
static dbi_driver_t *_get_driver(const char *filename, dbi_inst_t *inst) {
1166
1327
dbi_driver_t *driver;
1167
1328
void *dlhandle;
1168
1330
const char **custom_functions_list;
1169
1331
unsigned int idx = 0;
1170
1332
dbi_custom_function_t *prevcustom = NULL;
1171
1333
dbi_custom_function_t *custom = NULL;
1172
char function_name[256];
1174
1336
dlhandle = my_dlopen(filename, DLOPEN_FLAG); /* DLOPEN_FLAG defined by autoconf */
1190
1353
if ( /* nasty looking if block... is there a better way to do it? */
1191
1354
((driver->functions->register_driver = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_register_driver")) == NULL) ||
1192
1355
((driver->functions->initialize = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_initialize")) == NULL) ||
1356
((driver->functions->finalize = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_finalize")) == NULL) ||
1193
1357
((driver->functions->connect = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_connect")) == NULL) ||
1194
1358
((driver->functions->disconnect = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_disconnect")) == NULL) ||
1195
1359
((driver->functions->fetch_row = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_fetch_row")) == NULL) ||
1204
1368
((driver->functions->list_tables = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_list_tables")) == NULL) ||
1205
1369
((driver->functions->query = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_query")) == NULL) ||
1206
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) ||
1207
1377
((driver->functions->quote_string = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_quote_string")) == NULL) ||
1208
1378
((driver->functions->quote_binary = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_quote_binary")) == NULL) ||
1209
1379
((driver->functions->conn_quote_string = my_dlsym(dlhandle, DLSYM_PREFIX "dbd_conn_quote_string")) == NULL) ||
1222
1392
driver->functions->register_driver(&driver->info, &custom_functions_list, &driver->reserved_words);
1223
1393
driver->custom_functions = NULL; /* in case no custom functions are available */
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;
1406
else { /* the BSDs */
1407
symhandle = RTLD_NEXT;
1224
1410
while (custom_functions_list && custom_functions_list[idx] != NULL) {
1225
1411
custom = malloc(sizeof(dbi_custom_function_t));
1233
1419
custom->next = NULL;
1234
1420
custom->name = custom_functions_list[idx];
1235
snprintf(function_name, 256, DLSYM_PREFIX "dbd_%s", custom->name);
1236
custom->function_pointer = my_dlsym(dlhandle, function_name);
1237
if (!custom->function_pointer) {
1238
_free_custom_functions(driver);
1239
free(custom); /* not linked into the list yet */
1240
free(driver->functions);
1241
free(driver->filename);
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); */
1429
/* this usually fails because a function was
1430
renamed, is no longer available, or not
1431
yet available. Simply skip this
1433
free(custom); /* not linked into the list yet */
1245
1437
if (driver->custom_functions == NULL) {
1246
1438
driver->custom_functions = custom;
1289
1481
* operation = -1: remove conn
1290
1482
* = 0: just look for conn (return 1 if found, -1 if not)
1291
1483
* = 1: add conn */
1292
dbi_conn_t *curconn = rootconn;
1484
dbi_conn_t *curconn = conn->driver->dbi_inst->rootconn;
1293
1485
dbi_conn_t *prevconn = NULL;
1295
1487
if ((operation == -1) || (operation == 0)) {
1468
1660
/* hahaha! who woulda ever thunk strawberry's code would come in handy? */
1469
1661
// find first (highest) bit set; methods not using FP can be found at
1470
1662
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
1471
unsigned startbit = log(rangemin)/log(2);
1472
unsigned endbit = log(rangemax)/log(2);
1663
/* unsigned startbit = log(rangemin)/log(2); */
1664
/* unsigned endbit = log(rangemax)/log(2); */
1665
unsigned int startbit = 0;
1666
unsigned int endbit = 0;
1668
while (rangemin >>= 1) {
1672
while (rangemax >>= 1) {
1473
1676
// construct mask from startbit to endbit inclusive
1474
1677
unsigned attrib_mask = ((1<<(endbit+1))-1) ^ ((1<<startbit)-1);
1475
1678
return attribs & attrib_mask;