1
/* Copyright (C) 2004 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; either version 2 of the License, or
6
(at your option) any later version.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include "db_driver.h"
26
/* Global variables */
28
db_globals_t db_globals;
31
/* Static variables */
33
static sb_list_t drivers; /* list of available DB drivers */
35
/* DB drivers registrars */
38
int register_driver_mysql(sb_list_t *);
42
int register_driver_oracle(sb_list_t *);
46
int register_driver_pgsql(sb_list_t *);
49
/* Static functions */
51
static int db_parse_arguments(void);
52
db_error_t db_do_query(db_conn_t *, const char *, db_result_set_t *);
53
static void db_free_row(db_row_t *);
55
/* DB layer arguments */
57
static sb_arg_t db_args[] =
61
"specifies database driver to use ('help' to get list of available drivers)",
62
SB_ARG_TYPE_STRING, NULL
65
"db-ps-mode", "prepared statements usage mode {auto, disable}",
66
SB_ARG_TYPE_STRING, "auto"
69
{NULL, NULL, SB_ARG_TYPE_NULL, NULL}
73
/* Register available database drivers and command line arguments */
81
/* Register database drivers */
82
SB_LIST_INIT(&drivers);
84
register_driver_mysql(&drivers);
87
register_driver_oracle(&drivers);
90
register_driver_pgsql(&drivers);
93
/* Register command line options for each driver */
94
SB_LIST_FOR_EACH(pos, &drivers)
96
drv = SB_LIST_ENTRY(pos, db_driver_t, listitem);
97
if (drv->args != NULL)
98
sb_register_arg_set(drv->args);
100
/* Register general command line arguments for DB API */
101
sb_register_arg_set(db_args);
107
/* Print list of available drivers and their options */
110
void db_print_help(void)
115
log_text(LOG_NOTICE, "General database options:\n");
116
sb_print_options(db_args);
117
log_text(LOG_NOTICE, "");
119
log_text(LOG_NOTICE, "Compiled-in database drivers:");
120
SB_LIST_FOR_EACH(pos, &drivers)
122
drv = SB_LIST_ENTRY(pos, db_driver_t, listitem);
123
log_text(LOG_NOTICE, " %s - %s", drv->sname, drv->lname);
125
log_text(LOG_NOTICE, "");
126
SB_LIST_FOR_EACH(pos, &drivers)
128
drv = SB_LIST_ENTRY(pos, db_driver_t, listitem);
129
log_text(LOG_NOTICE, "%s options:", drv->sname);
130
sb_print_options(drv->args);
136
Initialize a driver specified by 'name' and return a handle to it
137
If NULL is passed as a name, then use the driver passed in --db-driver
142
db_driver_t *db_init(const char *name)
144
db_driver_t *drv = NULL;
147
if (SB_LIST_IS_EMPTY(&drivers))
149
log_text(LOG_FATAL, "No DB drivers available");
153
if (db_parse_arguments())
156
if (name == NULL && db_globals.driver == NULL)
158
drv = SB_LIST_ENTRY(SB_LIST_ITEM_NEXT(&drivers), db_driver_t, listitem);
159
/* Is it the only driver available? */
160
if (SB_LIST_ITEM_NEXT(&(drv->listitem)) ==
161
SB_LIST_ITEM_PREV(&(drv->listitem)))
162
log_text(LOG_INFO, "No DB drivers specified, using %s", drv->sname);
165
log_text(LOG_FATAL, "no database driver specified");
172
name = db_globals.driver;
174
SB_LIST_FOR_EACH(pos, &drivers)
176
drv = SB_LIST_ENTRY(pos, db_driver_t, listitem);
177
if (!strcmp(drv->sname, name))
184
log_text(LOG_FATAL, "invalid database driver name: '%s'", name);
188
db_globals.debug = sb_globals.debug;
190
/* Initialize database driver */
200
/* Describe database capabilities */
203
int db_describe(db_driver_t *drv, drv_caps_t *caps, const char *table)
205
if (drv->ops.describe == NULL)
208
return drv->ops.describe(caps, table);
212
/* Connect to database */
215
db_conn_t *db_connect(db_driver_t *drv)
219
con = (db_conn_t *)calloc(1, sizeof(db_conn_t));
224
if (drv->ops.connect(con))
234
/* Disconnect from database */
237
int db_disconnect(db_conn_t *con)
246
rc = drv->ops.disconnect(con);
253
/* Prepare statement */
256
db_stmt_t *db_prepare(db_conn_t *con, const char *query)
260
stmt = (db_stmt_t *)calloc(1, sizeof(db_stmt_t));
264
stmt->connection = con;
266
if (con->driver->ops.prepare(stmt, query))
276
/* Bind parameters for prepared statement */
279
int db_bind_param(db_stmt_t *stmt, db_bind_t *params, unsigned int len)
281
db_conn_t *con = stmt->connection;
283
if (con == NULL || con->driver == NULL)
286
return con->driver->ops.bind_param(stmt, params, len);
290
/* Execute prepared statement */
293
db_result_set_t *db_execute(db_stmt_t *stmt)
295
db_conn_t *con = stmt->connection;
296
db_result_set_t *rs = &con->rs;
298
if (con == NULL || con->driver == NULL)
300
log_text(LOG_DEBUG, "ERROR: exiting db_execute(), uninitialized connection");
305
memset(rs, 0, sizeof(db_result_set_t));
307
rs->statement = stmt;
308
rs->connection = con;
310
con->db_errno = con->driver->ops.execute(stmt, rs);
311
if (con->db_errno != SB_DB_ERROR_NONE)
313
log_text(LOG_DEBUG, "ERROR: exiting db_execute(), driver's execute method failed");
321
/* Fetch row into buffers bound by db_bind() */
324
int db_fetch(db_result_set_t *rs)
328
/* Is this a result set from a prepared statement? */
329
if (rs->statement == NULL)
332
con = rs->connection;
333
if (con == NULL || con->driver == NULL)
336
if (!rs->statement->emulated)
337
return con->driver->ops.fetch(rs);
339
/* NYI: Use emulation */
344
/* Return the number of rows in a result set */
347
unsigned long long db_num_rows(db_result_set_t *rs)
349
db_conn_t *con = rs->connection;
351
if (con == NULL || con->driver == NULL)
354
return con->driver->ops.num_rows(rs);
358
/* Fetch row from result set of a query */
361
db_row_t *db_fetch_row(db_result_set_t *rs)
363
db_conn_t *con = rs->connection;
365
/* Is this a result set of a non-prepared statement? */
366
if (rs->statement != NULL)
369
if (con == NULL || con->driver == NULL)
373
db_free_row(rs->row);
374
rs->row = (db_row_t *)calloc(1, sizeof(db_row_t));
378
if (con->driver->ops.fetch_row(rs, rs->row))
380
db_free_row(rs->row);
388
/* Execute non-prepared statement */
391
db_result_set_t *db_query(db_conn_t *con, const char *query)
393
db_result_set_t *rs = &con->rs;
395
if (con->driver == NULL)
398
memset(rs, 0, sizeof(db_result_set_t));
400
rs->connection = con;
402
con->db_errno = con->driver->ops.query(con, query, rs);
403
if (con->db_errno != SB_DB_ERROR_NONE)
410
/* Free result set */
413
int db_free_results(db_result_set_t *rs)
416
db_conn_t *con = rs->connection;
418
if (con == NULL || con->driver == NULL)
421
rc = con->driver->ops.free_results(rs);
424
db_free_row(rs->row);
430
/* Close prepared statement */
433
int db_close(db_stmt_t *stmt)
441
con = stmt->connection;
443
if (con == NULL || con->driver == NULL)
446
rc = con->driver->ops.close(stmt);
448
if (stmt->query != NULL)
453
if (stmt->bound_param != NULL)
455
free(stmt->bound_param);
456
stmt->bound_param = NULL;
464
/* Store result set from last query */
467
int db_store_results(db_result_set_t *rs)
469
db_conn_t *con = rs->connection;
471
if (con == NULL || con->driver == NULL)
472
return SB_DB_ERROR_FAILED;
474
return con->driver->ops.store_results(rs);
478
/* Uninitialize driver */
481
int db_done(db_driver_t *drv)
483
return drv->ops.done();
487
/* Return the error code for the last function */
490
db_error_t db_errno(db_conn_t *con)
492
return con->db_errno;
496
/* Parse command line arguments */
499
int db_parse_arguments(void)
503
s = sb_get_value_string("db-ps-mode");
505
if (!strcmp(s, "auto"))
506
db_globals.ps_mode = DB_PS_MODE_AUTO;
507
else if (!strcmp(s, "disable"))
508
db_globals.ps_mode = DB_PS_MODE_DISABLE;
511
log_text(LOG_FATAL, "Invalid value for db-ps-mode: %s", s);
515
db_globals.driver = sb_get_value_string("db-driver");
521
/* Produce character representation of a 'bind' variable */
524
int db_print_value(db_bind_t *var, char *buf, int buflen)
530
case DB_TYPE_TINYINT:
531
n = snprintf(buf, buflen, "%hhd", *(char *)var->buffer);
533
case DB_TYPE_SMALLINT:
534
n = snprintf(buf, buflen, "%hd", *(short *)var->buffer);
537
n = snprintf(buf, buflen, "%d", *(int *)var->buffer);
540
n = snprintf(buf, buflen, "%lld", *(long long *)var->buffer);
543
n = snprintf(buf, buflen, "%f", *(float *)var->buffer);
546
n = snprintf(buf, buflen, "%f", *(double *)var->buffer);
549
case DB_TYPE_VARCHAR:
550
n = snprintf(buf, buflen, "'%s'", (char *)var->buffer);
553
tm = (db_time_t *)var->buffer;
554
n = snprintf(buf, buflen, "'%d-%d-%d'", tm->year, tm->month, tm->day);
557
tm = (db_time_t *)var->buffer;
558
n = snprintf(buf, buflen, "'%d:%d:%d'", tm->hour, tm->minute,
561
case DB_TYPE_DATETIME:
562
case DB_TYPE_TIMESTAMP:
563
tm = (db_time_t *)var->buffer;
564
n = snprintf(buf, buflen, "'%d-%d-%d %d:%d:%d'", tm->year, tm->month,
565
tm->day, tm->hour, tm->minute, tm->second);
572
return (n < buflen) ? n : -1;
576
/* Free row fetched by db_fetch_row() */
579
void db_free_row(db_row_t *row)