/* Dynamic loading of the database backend.
* We use GLib's multiplatform dl() wrapper
* to open up libdbmysql or libdbpgsql and
* populate the global 'db' structure.
*
* (c) 2005 Aaron Stone <aaron@serendipity.cx>
*
* $Id: $
*/
#include <gmodule.h>
#include "config.h"
#include "debug.h"
#include "db.h"
#include "dbmodule.h"
static db_func_t *db = NULL;
extern db_param_t _db_params;
/* Returns:
* 1 on modules unsupported
* 0 on success
* -1 on failure to load module
* -2 on missing symbols
* -3 on memory error
*/
int db_load_driver(void)
{
GModule *module;
char *lib = NULL;
char *driver = NULL;
if (!g_module_supported()) {
trace(TRACE_FATAL, "%s,%s: loadable modules unsupported on this platform",
__FILE__, __func__);
return 1;
}
db = g_new0(db_func_t,1);
if (!db) {
trace(TRACE_FATAL, "%s,%s: cannot allocate memory",
__FILE__, __func__);
return -3;
}
if (strcasecmp(_db_params.driver, "PGSQL") == 0)
driver = "pgsql";
else if (strcasecmp(_db_params.driver, "POSTGRESQL") == 0)
driver = "pgsql";
else if (strcasecmp(_db_params.driver, "MYSQL") == 0)
driver = "mysql";
else if (strcasecmp(_db_params.driver, "SQLITE") == 0)
driver = "sqlite";
else
trace(TRACE_FATAL, "%s,%s: unsupported driver: %s,"
" please choose from MySQL, PGSQL, SQLite",
__FILE__, __func__,
_db_params.driver);
/* Try local build area, then dbmail lib paths, then system lib path. */
int i;
char *lib_path[] = {
"modules/.libs",
PREFIX "/lib",
PREFIX "/lib/dbmail",
NULL };
for (i = 0; i < 4; i++) {
lib = g_module_build_path(lib_path[i], driver);
module = g_module_open(lib, 0); // non-lazy bind.
if (module)
break;
}
/* If the list is exhausted without opening a module, we'll catch it. */
if (!module) {
trace(TRACE_FATAL, "%s,%s: cannot load %s",
__FILE__, __func__, g_module_error());
return -1;
}
if (!g_module_symbol(module, "db_connect", (gpointer)&db->connect )
|| !g_module_symbol(module, "db_disconnect", (gpointer)&db->disconnect )
|| !g_module_symbol(module, "db_check_connection", (gpointer)&db->check_connection )
|| !g_module_symbol(module, "db_query", (gpointer)&db->query )
|| !g_module_symbol(module, "db_insert_result", (gpointer)&db->insert_result )
|| !g_module_symbol(module, "db_num_rows", (gpointer)&db->num_rows )
|| !g_module_symbol(module, "db_num_fields", (gpointer)&db->num_fields )
|| !g_module_symbol(module, "db_get_result", (gpointer)&db->get_result )
|| !g_module_symbol(module, "db_free_result", (gpointer)&db->free_result )
|| !g_module_symbol(module, "db_escape_string", (gpointer)&db->escape_string )
|| !g_module_symbol(module, "db_escape_binary", (gpointer)&db->escape_binary )
|| !g_module_symbol(module, "db_do_cleanup", (gpointer)&db->do_cleanup )
|| !g_module_symbol(module, "db_get_length", (gpointer)&db->get_length )
|| !g_module_symbol(module, "db_get_affected_rows", (gpointer)&db->get_affected_rows )
|| !g_module_symbol(module, "db_use_msgbuf_result", (gpointer)&db->use_msgbuf_result )
|| !g_module_symbol(module, "db_store_msgbuf_result", (gpointer)&db->store_msgbuf_result )
|| !g_module_symbol(module, "db_get_sql", (gpointer)&db->get_sql )
|| !g_module_symbol(module, "db_set_result_set", (gpointer)&db->set_result_set )) {
trace(TRACE_FATAL, "%s,%s: cannot find function %s",
__FILE__, __func__, g_module_error());
return -2;
}
return 0;
}
/* This is the first db_* call anybody should make. */
int db_connect(void)
{
db_load_driver();
return db->connect();
}
/* But sometimes this gets called after help text or an
* error but without a matching db_connect before it. */
int db_disconnect(void)
{
if (!db) return 0;
db->disconnect();
g_free(db);
return 0;
}
int db_check_connection(void)
{ return db->check_connection(); }
int db_query(const char *the_query)
{ return db->query(the_query); }
u64_t db_insert_result(const char *sequence_identifier)
{ return db->insert_result(sequence_identifier); }
unsigned db_num_rows(void)
{ return db->num_rows(); }
unsigned db_num_fields(void)
{ return db->num_fields(); }
const char * db_get_result(unsigned row, unsigned field)
{ return db->get_result(row, field); }
void db_free_result(void)
{ return db->free_result(); }
unsigned long db_escape_string(char *to,
const char *from, unsigned long length)
{ return db->escape_string(to, from, length); }
unsigned long db_escape_binary(char *to,
const char *from, unsigned long length)
{ return db->escape_binary(to, from, length); }
int db_do_cleanup(const char **tables, int num_tables)
{ return db->do_cleanup(tables, num_tables); }
u64_t db_get_length(unsigned row, unsigned field)
{ return db->get_length(row, field); }
u64_t db_get_affected_rows(void)
{ return db->get_affected_rows(); }
void db_use_msgbuf_result(void)
{ db->use_msgbuf_result(); }
void db_store_msgbuf_result(void)
{ db->store_msgbuf_result(); }
void db_set_result_set(void *res)
{ db->set_result_set(res); }
const char * db_get_sql(sql_fragment_t frag)
{ return db->get_sql(frag); }
syntax highlighted by Code2HTML, v. 0.9.1