diff --git a/configure.ac b/configure.ac index 7d599f7..b1e7ab7 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,11 @@ AC_ARG_ENABLE(python, [compile_python=$enableval], [compile_python=yes]) +AC_ARG_WITH(mysql, + AC_HELP_STRING([--with-mysql],[path to mysql_config]), + [MYSQL_CONFIG=$with_mysql], + [MYSQL_CONFIG="default_mysql_config"]) + AM_CONDITIONAL([COMPILE_PYTHON], [test "${compile_python}" = "yes"]) AM_CONDITIONAL([WIN32], [test "$bwin32" = "true"]) @@ -124,6 +129,22 @@ if test "$bwin32" = "true"; then fi AC_SUBST(CONSOLE) +if test "x${MYSQL_CONFIG}" = "xdefault_mysql_config"; then + PKG_CHECK_MODULES(MYSQL, [mysqlclient], [have_mysql="yes"], [have_mysql="no"]) + if test "x${have_mysql}" = "xyes"; then + AC_SUBST(MYSQL_CFLAGS) + AC_SUBST(MYSQL_LIBS) + AC_DEFINE([HAVE_MYSQL], 1, [Define to 1 if MySQL support is enabled]) + fi +else + AC_MSG_CHECKING([for MySQL]) + MYSQL_CFLAGS=`${MYSQL_CONFIG} --include` + MYSQL_LIBS=`${MYSQL_CONFIG} --libs` + AC_MSG_RESULT([${MYSQL_CFLAGS}]) + AC_SUBST(MYSQL_CFLAGS) + AC_SUBST(MYSQL_LIBS) +fi + if test "$bwin32" = true; then LIB_WS32=-lws2_32 LIB_GDI32=-lgdi32 @@ -219,109 +240,6 @@ if test x${compile_python} = xyes; then fi fi -mysql="yes" -if test "$bwin32" != "true"; then - AC_MSG_CHECKING(for mysql in unix) - check_mysql_config() - { - AC_PATH_PROG([MYSQLCONFIG], [mysql_config], [no], [$PATH:/usr/local/bin:/usr/local/mysql/bin]) - if test "x$MYSQLCONFIG" = "xno" - then - AC_MSG_WARN([mysql_config is required to build seafile server with mysql]) - mysql="no" - fi - } - AC_ARG_WITH([mysql], - AS_HELP_STRING([--with-mysql(=)], - [Path is optional and if given should specify the full path to the MySQL - configure script, mysql_config. E.g. --with-mysql=//mysql_config]), - [ - if test "xno" = "x$with_mysql"; then - AC_MSG_RESULT([no]) - mysql="no" - else - AC_MSG_RESULT([yes]) - AC_CHECK_FILE([$with_mysql], [MYSQLCONFIG=$with_mysql], [check_mysql_config]) - fi - ], - [ - AC_MSG_RESULT([yes]) - check_mysql_config - ]) - if test "xyes" = "x$mysql"; then - tmp_CPPFLAGS=$CPPFLAGS - tmp_LDFLAGS=$LDFLAGS - CPPFLAGS="`$MYSQLCONFIG --include` $CPPFLAGS" - LDFLAGS="`$MYSQLCONFIG --libs` $LDFLAGS" - AC_CHECK_HEADERS([mysql.h], [], [mysql="no"]) - if test "xyes" = "x$mysql"; then - echo "found mysql client library" - MYSQL_CFLAGS=`$MYSQLCONFIG --include` - MYSQL_LIBS=`$MYSQLCONFIG --libs` - AC_SUBST(MYSQL_CFLAGS) - AC_SUBST(MYSQL_LIBS) - AC_DEFINE([HAVE_MYSQL], 1, [Define to 1 to enable mysql]) - fi - CPPFLAGS=$tmp_CPPFLAGS - LDFLAGS=$tmp_LDFLAGS - fi -else - AC_MSG_CHECKING(for mysql in windows) - AC_CHECK_HEADERS([mysql.h], [], [mysql="no"]) - if test "xyes" = "x$mysql"; then - AC_DEFINE([HAVE_MYSQL], 1, [Define to 1 to enable mysql]) - LDFLAGS="$LDFLAGS -lmysql -lws2_32" - fi -fi -AM_CONDITIONAL([WITH_MYSQL], test "xyes" = "x$mysql") - -postgresql="yes" -check_postgres_config() -{ - AC_PATH_PROG([PGCONFIG], [pg_config], [no], [$PATH:/usr/local/bin:/usr/local/pgsql/bin]) - if test "x$PGCONFIG" = "xno" - then - AC_MSG_WARN([pg_config is required to build seafile server with postgresql]) - postgresql="no" - fi -} -AC_MSG_CHECKING(for postgresql) -AC_ARG_WITH([postgresql], - AS_HELP_STRING([--with-postgresql(=)], - [Path is optional and if given should specify the full path to the PostgreSQL - configure script, pg_config. E.g. --with-postgresql=//pg_config]), - [ - if test "xno" = "x$with_postgresql"; then - AC_MSG_RESULT([no]) - postgresql="no" - else - AC_MSG_RESULT([yes]) - AC_CHECK_FILE([$with_postgresql], [PGCONFIG=$with_postgresql],[check_postgres_config]) - fi - ], - [ - AC_MSG_RESULT([yes]) - check_postgres_config - ]) -if test "xyes" = "x$postgresql"; then - tmp_CPPFLAGS=$CPPFLAGS - tmp_LDFLAGS=$LDFLAGS - CPPFLAGS="-I`$PGCONFIG --includedir` $CPPFLAGS" - LDFLAGS="-L`$PGCONFIG --libdir` $LDFLAGS" - AC_CHECK_HEADERS([libpq-fe.h], [], [postgresql="no"]) - if test "xyes" = "x$postgresql"; then - echo "found postgresql client library" - PGSQL_CFLAGS="-I`$PGCONFIG --includedir`" - PGSQL_LIBS="-L`$PGCONFIG --libdir` -lpq" - AC_SUBST(PGSQL_CFLAGS) - AC_SUBST(PGSQL_LIBS) - AC_DEFINE([HAVE_POSTGRESQL], 1, [Define to 1 to enable postgresql]) - fi - CPPFLAGS=$tmp_CPPFLAGS - LDFLAGS=$tmp_LDFLAGS -fi -AM_CONDITIONAL([WITH_POSTGRESQL], test "xyes" = "x$postgresql") - if test "${compile_ldap}" = "yes"; then if test "$bwin32" != true; then AC_CHECK_LIB(ldap, ldap_init, [have_ldap="yes"], @@ -348,7 +266,6 @@ AC_CONFIG_FILES( net/Makefile net/server/Makefile net/common/Makefile - net/common/db-wrapper/Makefile lib/Makefile tools/Makefile include/Makefile diff --git a/net/common/Makefile.am b/net/common/Makefile.am index 217a109..8e393c8 100644 --- a/net/common/Makefile.am +++ b/net/common/Makefile.am @@ -1,5 +1,3 @@ -SUBDIRS = db-wrapper - PROC_HEADER_FILES = \ $(addprefix processors/, \ rcvmsg-proc.h \ diff --git a/net/common/ccnet-db.c b/net/common/ccnet-db.c index 80ef07f..d6ecd3c 100644 --- a/net/common/ccnet-db.c +++ b/net/common/ccnet-db.c @@ -3,26 +3,81 @@ #include "log.h" -#include "db-wrapper/db-wrapper.h" #include "ccnet-db.h" -#define MAX_GET_CONNECTION_RETRIES 3 +#include +#ifdef HAVE_MYSQL +#include +#endif +#include +#include struct CcnetDB { int type; - DBConnPool *pool; }; +typedef struct DBConnection { + /* Empty */ +} DBConnection; + struct CcnetDBRow { - ResultSet *res; + /* Empty */ }; struct CcnetDBTrans { DBConnection *conn; }; +typedef struct DBOperations { + DBConnection* (*get_connection)(CcnetDB *db); + void (*release_connection)(DBConnection *conn); + int (*execute_sql_no_stmt)(DBConnection *conn, const char *sql); + int (*execute_sql)(DBConnection *conn, const char *sql, + int n, va_list args); + int (*query_foreach_row)(DBConnection *conn, + const char *sql, CcnetDBRowFunc callback, void *data, + int n, va_list args); + int (*row_get_column_count)(CcnetDBRow *row); + const char* (*row_get_column_string)(CcnetDBRow *row, int idx); + int (*row_get_column_int)(CcnetDBRow *row, int idx); + gint64 (*row_get_column_int64)(CcnetDBRow *row, int idx); +} DBOperations; + +static DBOperations db_ops; + #ifdef HAVE_MYSQL +/* MySQL Ops */ +static CcnetDB * +mysql_db_new (const char *host, + int port, + const char *user, + const char *password, + const char *db_name, + const char *unix_socket, + gboolean use_ssl, + const char *charset); +static DBConnection * +mysql_db_get_connection (CcnetDB *db); +static void +mysql_db_release_connection (DBConnection *vconn); +static int +mysql_db_execute_sql_no_stmt (DBConnection *vconn, const char *sql); +static int +mysql_db_execute_sql (DBConnection *vconn, const char *sql, int n, va_list args); +static int +mysql_db_query_foreach_row (DBConnection *vconn, const char *sql, + CcnetDBRowFunc callback, void *data, + int n, va_list args); +static int +mysql_db_row_get_column_count (CcnetDBRow *row); +static const char * +mysql_db_row_get_column_string (CcnetDBRow *row, int idx); +static int +mysql_db_row_get_column_int (CcnetDBRow *row, int idx); +static gint64 +mysql_db_row_get_column_int64 (CcnetDBRow *row, int idx); + CcnetDB * ccnet_db_new_mysql (const char *host, int port, @@ -36,742 +91,315 @@ ccnet_db_new_mysql (const char *host, { CcnetDB *db; - db = g_new0 (CcnetDB, 1); - if (!db) { - ccnet_warning ("Failed to alloc db structure.\n"); + db = mysql_db_new (host, port, user, passwd, db_name, unix_socket, use_ssl, charset); + if (!db) return NULL; - } - db->type = CCNET_DB_TYPE_MYSQL; - db->pool = db_conn_pool_new_mysql (host, user, passwd, port, db_name, - unix_socket, use_ssl, charset, max_connections); + db_ops.get_connection = mysql_db_get_connection; + db_ops.release_connection = mysql_db_release_connection; + db_ops.execute_sql_no_stmt = mysql_db_execute_sql_no_stmt; + db_ops.execute_sql = mysql_db_execute_sql; + db_ops.query_foreach_row = mysql_db_query_foreach_row; + db_ops.row_get_column_count = mysql_db_row_get_column_count; + db_ops.row_get_column_string = mysql_db_row_get_column_string; + db_ops.row_get_column_int = mysql_db_row_get_column_int; + db_ops.row_get_column_int64 = mysql_db_row_get_column_int64; return db; } #endif -#ifdef HAVE_POSTGRESQL - -CcnetDB * -ccnet_db_new_pgsql (const char *host, - unsigned int port, - const char *user, - const char *passwd, - const char *db_name, - const char *unix_socket, - int max_connections) -{ - CcnetDB *db; - - db = g_new0 (CcnetDB, 1); - if (!db) { - ccnet_warning ("Failed to alloc db structure.\n"); - return NULL; - } - - db->type = CCNET_DB_TYPE_PGSQL; - - db->pool = db_conn_pool_new_pgsql (host, port, user, passwd, db_name, unix_socket, - max_connections); - - return db; -} - -#endif +/* SQLite Ops */ +static CcnetDB * +sqlite_db_new (const char *db_path); +static DBConnection * +sqlite_db_get_connection (CcnetDB *db); +static void +sqlite_db_release_connection (DBConnection *vconn); +static int +sqlite_db_execute_sql_no_stmt (DBConnection *vconn, const char *sql); +static int +sqlite_db_execute_sql (DBConnection *vconn, const char *sql, int n, va_list args); +static int +sqlite_db_query_foreach_row (DBConnection *vconn, const char *sql, + CcnetDBRowFunc callback, void *data, + int n, va_list args); +static int +sqlite_db_row_get_column_count (CcnetDBRow *row); +static const char * +sqlite_db_row_get_column_string (CcnetDBRow *row, int idx); +static int +sqlite_db_row_get_column_int (CcnetDBRow *row, int idx); +static gint64 +sqlite_db_row_get_column_int64 (CcnetDBRow *row, int idx); CcnetDB * ccnet_db_new_sqlite (const char *db_path) { CcnetDB *db; - db = g_new0 (CcnetDB, 1); - if (!db) { - ccnet_warning ("Failed to alloc db structure.\n"); + db = sqlite_db_new (db_path); + if (!db) return NULL; - } - db->type = CCNET_DB_TYPE_SQLITE; - db->pool = db_conn_pool_new_sqlite (db_path, 10); + db_ops.get_connection = sqlite_db_get_connection; + db_ops.release_connection = sqlite_db_release_connection; + db_ops.execute_sql_no_stmt = sqlite_db_execute_sql_no_stmt; + db_ops.execute_sql = sqlite_db_execute_sql; + db_ops.query_foreach_row = sqlite_db_query_foreach_row; + db_ops.row_get_column_count = sqlite_db_row_get_column_count; + db_ops.row_get_column_string = sqlite_db_row_get_column_string; + db_ops.row_get_column_int = sqlite_db_row_get_column_int; + db_ops.row_get_column_int64 = sqlite_db_row_get_column_int64; return db; } -void -ccnet_db_free (CcnetDB *db) -{ - db_conn_pool_free (db->pool); - g_free (db); -} - int ccnet_db_type (CcnetDB *db) { return db->type; } -static DBConnection * -get_db_connection (CcnetDB *db) -{ - DBConnection *conn; - GError *error = NULL; - - conn = db_conn_pool_get_connection (db->pool, &error); - - if (!conn) { - ccnet_warning ("Failed to get database connection: %s.\n", error->message); - g_clear_error (&error); - } - - return conn; -} - int ccnet_db_query (CcnetDB *db, const char *sql) { - GError *error = NULL; - int ret = 0; - - DBConnection *conn = get_db_connection (db); + DBConnection *conn = db_ops.get_connection (db); if (!conn) return -1; - if (!db_connection_execute (conn, sql, &error)) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - ret = -1; - } - - db_connection_close (conn); + int ret; + ret = db_ops.execute_sql_no_stmt (conn, sql); + db_ops.release_connection (conn); return ret; } gboolean ccnet_db_check_for_existence (CcnetDB *db, const char *sql, gboolean *db_err) { - DBConnection *conn; - ResultSet *result; - gboolean ret = TRUE; - GError *error = NULL; - - *db_err = FALSE; - - conn = get_db_connection (db); - if (!conn) { - *db_err = TRUE; - return FALSE; - } - - result = db_connection_execute_query (conn, sql, &error); - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - *db_err = TRUE; - ret = FALSE; - goto out; - } - - ret = result_set_next (result, &error); - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - *db_err = TRUE; - } - -out: - db_connection_close (conn); - - return ret; + return ccnet_db_statement_exists (db, sql, db_err, 0); } int ccnet_db_foreach_selected_row (CcnetDB *db, const char *sql, CcnetDBRowFunc callback, void *data) { - DBConnection *conn; - ResultSet *result; - CcnetDBRow ccnet_row; - int n_rows = 0; - GError *error = NULL; - - conn = get_db_connection (db); - if (!conn) - return -1; - - result = db_connection_execute_query (conn, sql, &error); - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - n_rows = -1; - goto out; - } - - ccnet_row.res = result; - - while (result_set_next (result, &error)) { - n_rows++; - if (!callback (&ccnet_row, data)) - break; - } - - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - n_rows = -1; - } - -out: - db_connection_close (conn); - return n_rows; + return ccnet_db_statement_foreach_row (db, sql, callback, data, 0); } const char * ccnet_db_row_get_column_text (CcnetDBRow *row, guint32 idx) { - GError *error = NULL; - g_return_val_if_fail (idx < result_set_get_column_count(row->res), NULL); + g_return_val_if_fail (idx < db_ops.row_get_column_count(row), NULL); - return result_set_get_string (row->res, idx, &error); + return db_ops.row_get_column_string (row, idx); } int ccnet_db_row_get_column_int (CcnetDBRow *row, guint32 idx) { - GError *error = NULL; - g_return_val_if_fail (idx < result_set_get_column_count(row->res), -1); + g_return_val_if_fail (idx < db_ops.row_get_column_count(row), -1); - return result_set_get_int (row->res, idx, &error); + return db_ops.row_get_column_int (row, idx); } gint64 ccnet_db_row_get_column_int64 (CcnetDBRow *row, guint32 idx) { - GError *error = NULL; - g_return_val_if_fail (idx < result_set_get_column_count(row->res), -1); + g_return_val_if_fail (idx < db_ops.row_get_column_count(row), -1); - return result_set_get_int64 (row->res, idx, &error); + return db_ops.row_get_column_int64 (row, idx); } int ccnet_db_get_int (CcnetDB *db, const char *sql) { - int ret = -1; - DBConnection *conn; - ResultSet *result; - CcnetDBRow ccnet_row; - GError *error = NULL; - - conn = get_db_connection (db); - if (!conn) - return -1; - - result = db_connection_execute_query (conn, sql, &error); - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - goto out; - } - - ccnet_row.res = result; - if (!result_set_next (result, &error)) { - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - } - goto out; - } - - ret = ccnet_db_row_get_column_int (&ccnet_row, 0); - -out: - db_connection_close (conn); - return ret; + return ccnet_db_statement_get_int (db, sql, 0); } gint64 ccnet_db_get_int64 (CcnetDB *db, const char *sql) { - gint64 ret = -1; - DBConnection *conn; - ResultSet *result; - CcnetDBRow ccnet_row; - GError *error = NULL; - - conn = get_db_connection (db); - if (!conn) - return -1; - - result = db_connection_execute_query (conn, sql, &error); - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - goto out; - } - - ccnet_row.res = result; - if (!result_set_next (result, &error)) { - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - } - goto out; - } - - ret = ccnet_db_row_get_column_int64 (&ccnet_row, 0); - -out: - db_connection_close (conn); - return ret; + return ccnet_db_statement_get_int64 (db, sql, 0); } char * ccnet_db_get_string (CcnetDB *db, const char *sql) { - char *ret = NULL; - const char *s; - DBConnection *conn; - ResultSet *result; - CcnetDBRow ccnet_row; - GError *error = NULL; - - conn = get_db_connection (db); - if (!conn) - return NULL; - - result = db_connection_execute_query (conn, sql, &error); - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - goto out; - } - - ccnet_row.res = result; - if (!result_set_next (result, &error)) { - if (error) { - ccnet_warning ("Error exec query %s: %s.\n", sql, error->message); - g_clear_error (&error); - } - goto out; - } - - s = ccnet_db_row_get_column_text (&ccnet_row, 0); - ret = g_strdup(s); - -out: - db_connection_close (conn); - return ret; -} - -char * -ccnet_db_escape_string (CcnetDB *db, const char *from) -{ - const char *p = from; - char *to, *q; - - to = g_malloc0 (2*strlen(from)+1); - q = to; - - while (*p != '\0') { - if (*p == '\'' || *p == '\\' || *p == '"') { - *q = *p; - *(++q) = *p; - } else - *q = *p; - ++p; - ++q; - } - - return to; -} - -gboolean -pgsql_index_exists (CcnetDB *db, const char *index_name) -{ - char sql[256]; - gboolean db_err = FALSE; - - snprintf (sql, sizeof(sql), - "SELECT 1 FROM pg_class WHERE relname='%s'", - index_name); - return ccnet_db_check_for_existence (db, sql, &db_err); -} - -/* Prepared Statements */ - -struct CcnetDBStatement { - DBStmt *p; - DBConnection *conn; -}; -typedef struct CcnetDBStatement CcnetDBStatement; - -CcnetDBStatement * -ccnet_db_prepare_statement (CcnetDB *db, const char *sql) -{ - DBStmt *p; - CcnetDBStatement *ret = g_new0 (CcnetDBStatement, 1); - GError *error = NULL; - - DBConnection *conn = get_db_connection (db); - if (!conn) { - g_free (ret); - return NULL; - } - - p = db_connection_prepare_statement (conn, sql, &error); - if (!p) { - ccnet_warning ("Error prepare statement %s: %s.\n", sql, error->message); - g_clear_error (&error); - g_free (ret); - db_connection_close (conn); - return NULL; - } - - ret->p = p; - ret->conn = conn; - - return ret; -} - -void -ccnet_db_statement_free (CcnetDBStatement *p) -{ - db_connection_close (p->conn); - g_free (p); -} - -int -ccnet_db_statement_set_int (DBStmt *p, int idx, int x) -{ - GError *error = NULL; - - if (!db_stmt_set_int (p, idx, x, &error)) { - ccnet_warning ("Error set int in prep stmt: %s.\n", error->message); - g_clear_error (&error); - return -1; - } - - return 0; -} - -int -ccnet_db_statement_set_string (DBStmt *p, int idx, const char *s) -{ - GError *error = NULL; - - if (!db_stmt_set_string (p, idx, s, &error)) { - ccnet_warning ("Error set string in prep stmt: %s.\n", error->message); - g_clear_error (&error); - return -1; - } - - return 0; -} - -int -ccnet_db_statement_set_int64 (DBStmt *p, int idx, gint64 x) -{ - GError *error = NULL; - - if (!db_stmt_set_int64 (p, idx, x, &error)) { - ccnet_warning ("Error set int64 in prep stmt: %s.\n", error->message); - g_clear_error (&error); - return -1; - } - - return 0; -} - -static int -set_parameters_va (DBStmt *p, int n, va_list args) -{ - int i; - const char *type; - - for (i = 0; i < n; ++i) { - type = va_arg (args, const char *); - if (strcmp(type, "int") == 0) { - int x = va_arg (args, int); - if (ccnet_db_statement_set_int (p, i, x) < 0) - return -1; - } else if (strcmp (type, "int64") == 0) { - gint64 x = va_arg (args, gint64); - if (ccnet_db_statement_set_int64 (p, i, x) < 0) - return -1; - } else if (strcmp (type, "string") == 0) { - const char *s = va_arg (args, const char *); - if (ccnet_db_statement_set_string (p, i, s) < 0) - return -1; - } else { - ccnet_warning ("BUG: invalid prep stmt parameter type %s.\n", type); - g_return_val_if_reached (-1); - } - } - - return 0; + return ccnet_db_statement_get_string (db, sql, 0); } int ccnet_db_statement_query (CcnetDB *db, const char *sql, int n, ...) { - CcnetDBStatement *p; - int ret = 0; - GError *error = NULL; + int ret; + DBConnection *conn = NULL; - p = ccnet_db_prepare_statement (db, sql); - if (!p) + conn = db_ops.get_connection (db); + if (!conn) return -1; va_list args; va_start (args, n); - if (set_parameters_va (p->p, n, args) < 0) { - ccnet_db_statement_free (p); - va_end (args); - return -1; - } + ret = db_ops.execute_sql (conn, sql, n, args); va_end (args); - if (!db_stmt_execute (p->p, &error)) { - ccnet_warning ("Error execute prep stmt: %s.\n", error->message); - g_clear_error (&error); - ret = -1; - } + db_ops.release_connection (conn); - ccnet_db_statement_free (p); return ret; } gboolean -ccnet_db_statement_exists (CcnetDB *db, const char *sql, int n, ...) +ccnet_db_statement_exists (CcnetDB *db, const char *sql, gboolean *db_err, int n, ...) { - CcnetDBStatement *p; - ResultSet *result; - gboolean ret = TRUE; - GError *error = NULL; + int n_rows; + DBConnection *conn = NULL; - p = ccnet_db_prepare_statement (db, sql); - if (!p) { + conn = db_ops.get_connection(db); + if (!conn) return FALSE; - } va_list args; va_start (args, n); - if (set_parameters_va (p->p, n, args) < 0) { - ccnet_db_statement_free (p); - va_end (args); - return FALSE; - } + n_rows = db_ops.query_foreach_row (conn, sql, NULL, NULL, n, args); va_end (args); - result = db_stmt_execute_query (p->p, &error); - if (error) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); - ret = FALSE; - goto out; + db_ops.release_connection(conn); + + if (n_rows < 0) { + *db_err = TRUE; + return FALSE; + } else { + *db_err = FALSE; + return (n_rows != 0); } - - if (!result_set_next (result, &error)) - ret = FALSE; - - if (error) { - ccnet_warning ("Error get next result from prep stmt: %s.\n", error->message); - g_clear_error (&error); - } - -out: - ccnet_db_statement_free (p); - return ret; } int -ccnet_db_statement_foreach_row (CcnetDB *db, - const char *sql, - CcnetDBRowFunc callback, void *data, - int n, ...) +ccnet_db_statement_foreach_row (CcnetDB *db, const char *sql, + CcnetDBRowFunc callback, void *data, + int n, ...) { - CcnetDBStatement *p; - ResultSet *result; - CcnetDBRow ccnet_row; - int n_rows = 0; - GError *error = NULL; + int ret; + DBConnection *conn = NULL; - p = ccnet_db_prepare_statement (db, sql); - if (!p) + conn = db_ops.get_connection (db); + if (!conn) return -1; va_list args; va_start (args, n); - if (set_parameters_va (p->p, n, args) < 0) { - ccnet_db_statement_free (p); - va_end (args); - return -1; - } + ret = db_ops.query_foreach_row (conn, sql, callback, data, n, args); va_end (args); - result = db_stmt_execute_query (p->p, &error); - if (error) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); - n_rows = -1; - goto out; - } + db_ops.release_connection (conn); - ccnet_row.res = result; + return ret; +} - while (result_set_next (result, &error)) { - n_rows++; - if (!callback (&ccnet_row, data)) - break; - } +static gboolean +get_int_cb (CcnetDBRow *row, void *data) +{ + int *pret = (int*)data; - if (error) { - ccnet_warning ("Error get next result from prep stmt: %s.\n", error->message); - g_clear_error (&error); - n_rows = -1; - } + *pret = ccnet_db_row_get_column_int (row, 0); -out: - ccnet_db_statement_free (p); - return n_rows; + return FALSE; } int ccnet_db_statement_get_int (CcnetDB *db, const char *sql, int n, ...) { - CcnetDBStatement *p; int ret = -1; - ResultSet *result; - CcnetDBRow ccnet_row; - GError *error = NULL; + int rc; + DBConnection *conn = NULL; - p = ccnet_db_prepare_statement (db, sql); - if (!p) + conn = db_ops.get_connection (db); + if (!conn) return -1; va_list args; va_start (args, n); - if (set_parameters_va (p->p, n, args) < 0) { - ccnet_db_statement_free (p); - va_end (args); - return -1; - } + rc = db_ops.query_foreach_row (conn, sql, get_int_cb, &ret, n, args); va_end (args); - result = db_stmt_execute_query (p->p, &error); - if (error) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); - goto out; - } + db_ops.release_connection (conn); - ccnet_row.res = result; - if (!result_set_next (result, &error)) { - if (error) { - ccnet_warning ("Error get next result from prep stmt: %s.\n", error->message); - g_clear_error (&error); - } - goto out; - } + if (rc < 0) + return -1; - ret = ccnet_db_row_get_column_int (&ccnet_row, 0); - -out: - ccnet_db_statement_free (p); return ret; } +static gboolean +get_int64_cb (CcnetDBRow *row, void *data) +{ + gint64 *pret = (gint64*)data; + + *pret = ccnet_db_row_get_column_int64 (row, 0); + + return FALSE; +} + gint64 ccnet_db_statement_get_int64 (CcnetDB *db, const char *sql, int n, ...) { - CcnetDBStatement *p; gint64 ret = -1; - ResultSet *result; - CcnetDBRow ccnet_row; - GError *error = NULL; + int rc; + DBConnection *conn = NULL; - p = ccnet_db_prepare_statement (db, sql); - if (!p) + conn = db_ops.get_connection (db); + if (!conn) return -1; va_list args; va_start (args, n); - if (set_parameters_va (p->p, n, args) < 0) { - ccnet_db_statement_free (p); - va_end (args); + rc = db_ops.query_foreach_row (conn, sql, get_int64_cb, &ret, n, args); + va_end(args); + + db_ops.release_connection (conn); + + if (rc < 0) return -1; - } - va_end (args); - result = db_stmt_execute_query (p->p, &error); - if (error) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); - goto out; - } - - ccnet_row.res = result; - if (!result_set_next (result, &error)) { - if (error) { - ccnet_warning ("Error get next result from prep stmt: %s.\n", error->message); - g_clear_error (&error); - } - goto out; - } - - ret = ccnet_db_row_get_column_int64 (&ccnet_row, 0); - -out: - ccnet_db_statement_free (p); return ret; } +static gboolean +get_string_cb (CcnetDBRow *row, void *data) +{ + char **pret = (char**)data; + + *pret = g_strdup(ccnet_db_row_get_column_text (row, 0)); + + return FALSE; +} + char * ccnet_db_statement_get_string (CcnetDB *db, const char *sql, int n, ...) { - CcnetDBStatement *p; char *ret = NULL; - const char *s; - ResultSet *result; - CcnetDBRow ccnet_row; - GError *error = NULL; + int rc; + DBConnection *conn = NULL; - p = ccnet_db_prepare_statement (db, sql); - if (!p) + conn = db_ops.get_connection (db); + if (!conn) return NULL; va_list args; va_start (args, n); - if (set_parameters_va (p->p, n, args) < 0) { - ccnet_db_statement_free (p); - va_end (args); + rc = db_ops.query_foreach_row (conn, sql, get_string_cb, &ret, n, args); + va_end(args); + + db_ops.release_connection (conn); + + if (rc < 0) return NULL; - } - va_end (args); - result = db_stmt_execute_query (p->p, &error); - if (error) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); - goto out; - } - - ccnet_row.res = result; - if (!result_set_next (result, &error)) { - if (error) { - ccnet_warning ("Error get next result from prep stmt: %s.\n", error->message); - g_clear_error (&error); - } - goto out; - } - - s = ccnet_db_row_get_column_text (&ccnet_row, 0); - ret = g_strdup(s); - -out: - ccnet_db_statement_free (p); return ret; } @@ -780,28 +408,19 @@ out: CcnetDBTrans * ccnet_db_begin_transaction (CcnetDB *db) { - DBConnection *conn; - CcnetDBTrans *trans; - GError *error = NULL; + CcnetDBTrans *trans = NULL; + DBConnection *conn = db_ops.get_connection(db); + if (!conn) { + return trans; + } + + if (db_ops.execute_sql_no_stmt (conn, "BEGIN") < 0) { + db_ops.release_connection (conn); + return trans; + } trans = g_new0 (CcnetDBTrans, 1); - if (!trans) - return NULL; - - conn = get_db_connection (db); - if (!conn) { - g_free (trans); - return NULL; - } - trans->conn = conn; - if (!db_connection_begin_transaction (trans->conn, &error)) { - ccnet_warning ("Start transaction failed: %s.\n", error->message); - g_clear_error (&error); - db_connection_close (trans->conn); - g_free (trans); - return NULL; - } return trans; } @@ -809,7 +428,7 @@ ccnet_db_begin_transaction (CcnetDB *db) void ccnet_db_trans_close (CcnetDBTrans *trans) { - db_connection_close (trans->conn); + db_ops.release_connection (trans->conn); g_free (trans); } @@ -817,11 +436,8 @@ int ccnet_db_commit (CcnetDBTrans *trans) { DBConnection *conn = trans->conn; - GError *error = NULL; - if (!db_connection_commit (conn, &error)) { - ccnet_warning ("Commit failed: %s.\n", error->message); - g_clear_error (&error); + if (db_ops.execute_sql_no_stmt (conn, "COMMIT") < 0) { return -1; } @@ -832,58 +448,25 @@ int ccnet_db_rollback (CcnetDBTrans *trans) { DBConnection *conn = trans->conn; - GError *error = NULL; - if (!db_connection_rollback(conn, &error)) { - ccnet_warning ("Rollback failed: %s.\n", error->message); - g_clear_error (&error); + if (db_ops.execute_sql_no_stmt (conn, "ROLLBACK") < 0) { return -1; } return 0; } -static DBStmt * -trans_prepare_statement (DBConnection *conn, const char *sql) -{ - DBStmt *p; - GError *error = NULL; - - p = db_connection_prepare_statement (conn, sql, &error); - if (!p) { - ccnet_warning ("Error prepare statement %s: %s.\n", sql, error->message); - g_clear_error (&error); - return NULL; - } - - return p; -} - int ccnet_db_trans_query (CcnetDBTrans *trans, const char *sql, int n, ...) { - DBStmt *p; - GError *error = NULL; - - p = trans_prepare_statement (trans->conn, sql); - if (!p) - return -1; + int ret; va_list args; va_start (args, n); - if (set_parameters_va (p, n, args) < 0) { - va_end (args); - return -1; - } + ret = db_ops.execute_sql (trans->conn, sql, n, args); va_end (args); - if (!db_stmt_execute (p, &error)) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); - return -1; - } - - return 0; + return ret; } gboolean @@ -892,47 +475,20 @@ ccnet_db_trans_check_for_existence (CcnetDBTrans *trans, gboolean *db_err, int n, ...) { - ResultSet *result; - gboolean ret = TRUE; - GError *error = NULL; - - *db_err = FALSE; - - DBStmt *p; - - p = trans_prepare_statement (trans->conn, sql); - if (!p) { - *db_err = TRUE; - return FALSE; - } + int n_rows; va_list args; va_start (args, n); - if (set_parameters_va (p, n, args) < 0) { - *db_err = TRUE; - va_end (args); - return FALSE; - } + n_rows = db_ops.query_foreach_row (trans->conn, sql, NULL, NULL, n, args); va_end (args); - result = db_stmt_execute_query (p, &error); - if (error) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); + if (n_rows < 0) { *db_err = TRUE; return FALSE; + } else { + *db_err = FALSE; + return (n_rows != 0); } - - if (!result_set_next (result, &error)) - ret = FALSE; - - if (error) { - ccnet_warning ("Error get next result from prep stmt: %s.\n", error->message); - g_clear_error (&error); - *db_err = TRUE; - } - - return ret; } int @@ -940,45 +496,766 @@ ccnet_db_trans_foreach_selected_row (CcnetDBTrans *trans, const char *sql, CcnetDBRowFunc callback, void *data, int n, ...) { - ResultSet *result; - CcnetDBRow ccnet_row; - int n_rows = 0; - GError *error = NULL; - - DBStmt *p; - - p = trans_prepare_statement (trans->conn, sql); - if (!p) - return FALSE; + int ret; va_list args; va_start (args, n); - if (set_parameters_va (p, n, args) < 0) { - va_end (args); - return -1; - } + ret = db_ops.query_foreach_row (trans->conn, sql, callback, data, n, args); va_end (args); - result = db_stmt_execute_query (p, &error); - if (error) { - ccnet_warning ("Error exec prep stmt: %s.\n", error->message); - g_clear_error (&error); + return ret; +} + +#ifdef HAVE_MYSQL + +/* MySQL DB */ + +typedef struct MySQLDB { + struct CcnetDB parent; + char *host; + char *user; + char *password; + unsigned int port; + char *db_name; + char *unix_socket; + gboolean use_ssl; + char *charset; +} MySQLDB; + +typedef struct MySQLDBConnection { + struct DBConnection parent; + MYSQL *db_conn; +} MySQLDBConnection; + +static CcnetDB * +mysql_db_new (const char *host, + int port, + const char *user, + const char *password, + const char *db_name, + const char *unix_socket, + gboolean use_ssl, + const char *charset) +{ + MySQLDB *db = g_new0 (MySQLDB, 1); + + db->host = g_strdup (host); + db->user = g_strdup (user); + db->password = g_strdup (password); + db->port = port; + db->db_name = g_strdup(db_name); + db->unix_socket = g_strdup(unix_socket); + db->use_ssl = use_ssl; + db->charset = g_strdup(charset); + + mysql_library_init (0, NULL, NULL); + + return (CcnetDB *)db; +} + +static DBConnection * +mysql_db_get_connection (CcnetDB *vdb) +{ + MySQLDB *db = (MySQLDB *)vdb; + my_bool yes = 1; + int conn_timeout = 1; + MYSQL *db_conn; + MySQLDBConnection *conn = NULL; + + db_conn = mysql_init (NULL); + if (!db_conn) { + ccnet_warning ("Failed to init mysql connection object.\n"); + return NULL; + } + + if (db->use_ssl) + mysql_ssl_set(db_conn, 0,0,0,0,0); + + if (db->charset) + mysql_options(db_conn, MYSQL_SET_CHARSET_NAME, db->charset); + + mysql_options(db_conn, MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&conn_timeout); + mysql_options(db_conn, MYSQL_OPT_RECONNECT, (const char*)&yes); + + if (!mysql_real_connect(db_conn, db->host, db->user, db->password, + db->db_name, db->port, + db->unix_socket, CLIENT_MULTI_STATEMENTS)) { + ccnet_warning ("Failed to connect to MySQL: %s\n", mysql_error(db_conn)); + mysql_close (db_conn); + return NULL; + } + + conn = g_new0 (MySQLDBConnection, 1); + conn->db_conn = db_conn; + + return (DBConnection *)conn; +} + +static void +mysql_db_release_connection (DBConnection *vconn) +{ + if (!vconn) + return; + + MySQLDBConnection *conn = (MySQLDBConnection *)vconn; + + mysql_close (conn->db_conn); + + g_free (conn); +} + +static int +mysql_db_execute_sql_no_stmt (DBConnection *vconn, const char *sql) +{ + MySQLDBConnection *conn = (MySQLDBConnection *)vconn; + + if (mysql_query (conn->db_conn, sql) != 0) { + ccnet_warning ("Failed to execute sql %s: %s\n", sql, mysql_error(conn->db_conn)); return -1; } - ccnet_row.res = result; + return 0; +} - while (result_set_next (result, &error)) { - n_rows++; - if (!callback (&ccnet_row, data)) +static MYSQL_STMT * +_prepare_stmt_mysql (MYSQL *db, const char *sql) +{ + MYSQL_STMT *stmt; + + stmt = mysql_stmt_init (db); + if (!stmt) { + ccnet_warning ("mysql_stmt_init failed.\n"); + return NULL; + } + + if (mysql_stmt_prepare (stmt, sql, strlen(sql)) != 0) { + ccnet_warning ("Failed to prepare sql %s: %s\n", sql, mysql_stmt_error(stmt)); + mysql_stmt_close (stmt); + return NULL; + } + + return stmt; +} + +static int +_bind_params_mysql (MYSQL_STMT *stmt, MYSQL_BIND *params, int n, va_list args) +{ + int i; + const char *type; + + for (i = 0; i < n; ++i) { + type = va_arg (args, const char *); + if (strcmp(type, "int") == 0) { + int x = va_arg (args, int); + int *pval = g_new (int, 1); + *pval = x; + params[i].buffer_type = MYSQL_TYPE_LONG; + params[i].buffer = pval; + params[i].is_null = 0; + } else if (strcmp (type, "int64") == 0) { + gint64 x = va_arg (args, gint64); + gint64 *pval = g_new (gint64, 1); + *pval = x; + params[i].buffer_type = MYSQL_TYPE_LONGLONG; + params[i].buffer = pval; + params[i].is_null = 0; + } else if (strcmp (type, "string") == 0) { + const char *s = va_arg (args, const char *); + static my_bool yes = TRUE; + params[i].buffer_type = MYSQL_TYPE_STRING; + params[i].buffer = g_strdup(s); + unsigned long *plen = g_new (unsigned long, 1); + params[i].length = plen; + if (!s) { + *plen = 0; + params[i].buffer_length = 0; + params[i].is_null = &yes; + } else { + *plen = strlen(s); + params[i].buffer_length = *plen + 1; + params[i].is_null = 0; + } + } else { + ccnet_warning ("BUG: invalid prep stmt parameter type %s.\n", type); + g_return_val_if_reached (-1); + } + } + + if (mysql_stmt_bind_param (stmt, params) != 0) { + return -1; + } + + return 0; +} + +static int +mysql_db_execute_sql (DBConnection *vconn, const char *sql, int n, va_list args) +{ + MySQLDBConnection *conn = (MySQLDBConnection *)vconn; + MYSQL *db = conn->db_conn; + MYSQL_STMT *stmt = NULL; + MYSQL_BIND *params = NULL; + int ret = 0; + + stmt = _prepare_stmt_mysql (db, sql); + if (!stmt) { + return -1; + } + + if (n > 0) { + params = g_new0 (MYSQL_BIND, n); + if (_bind_params_mysql (stmt, params, n, args) < 0) { + ccnet_warning ("Failed to bind parameters for %s: %s.\n", + sql, mysql_stmt_error(stmt)); + ret = -1; + goto out; + } + } + + if (mysql_stmt_execute (stmt) != 0) { + ccnet_warning ("Failed to execute sql %s: %s\n", sql, mysql_stmt_error(stmt)); + ret = -1; + goto out; + } + +out: + if (stmt) + mysql_stmt_close (stmt); + if (params) { + int i; + for (i = 0; i < n; ++i) { + g_free (params[i].buffer); + g_free (params[i].length); + } + g_free (params); + } + return ret; +} + +typedef struct MySQLDBRow { + CcnetDBRow parent; + int column_count; + MYSQL_STMT *stmt; + MYSQL_BIND *results; + /* Used when returned columns are truncated. */ + MYSQL_BIND *new_binds; +} MySQLDBRow; + +#define DEFAULT_MYSQL_COLUMN_SIZE 1024 + +static int +mysql_db_query_foreach_row (DBConnection *vconn, const char *sql, + CcnetDBRowFunc callback, void *data, + int n, va_list args) +{ + MySQLDBConnection *conn = (MySQLDBConnection *)vconn; + MYSQL *db = conn->db_conn; + MYSQL_STMT *stmt = NULL; + MYSQL_BIND *params = NULL; + MySQLDBRow row; + int nrows = 0; + int i; + + memset (&row, 0, sizeof(row)); + + stmt = _prepare_stmt_mysql (db, sql); + if (!stmt) { + return -1; + } + + if (n > 0) { + params = g_new0 (MYSQL_BIND, n); + if (_bind_params_mysql (stmt, params, n, args) < 0) { + nrows = -1; + goto out; + } + } + + if (mysql_stmt_execute (stmt) != 0) { + ccnet_warning ("Failed to execute sql %s: %s\n", sql, mysql_stmt_error(stmt)); + nrows = -1; + goto out; + } + + row.column_count = mysql_stmt_field_count (stmt); + row.stmt = stmt; + row.results = g_new0 (MYSQL_BIND, row.column_count); + for (i = 0; i < row.column_count; ++i) { + row.results[i].buffer = g_malloc (DEFAULT_MYSQL_COLUMN_SIZE + 1); + /* Ask MySQL to convert fields to string, to avoid the trouble of + * checking field types. + */ + row.results[i].buffer_type = MYSQL_TYPE_STRING; + row.results[i].buffer_length = DEFAULT_MYSQL_COLUMN_SIZE; + row.results[i].length = g_new0 (unsigned long, 1); + row.results[i].is_null = g_new0 (my_bool, 1); + } + row.new_binds = g_new0 (MYSQL_BIND, row.column_count); + + if (mysql_stmt_bind_result (stmt, row.results) != 0) { + ccnet_warning ("Failed to bind result for sql %s: %s\n", sql, mysql_stmt_error(stmt)); + nrows = -1; + goto out; + } + + int rc; + gboolean next_row = TRUE; + while (1) { + rc = mysql_stmt_fetch (stmt); + if (rc == 1) { + ccnet_warning ("Failed to fetch result for sql %s: %s\n", + sql, mysql_stmt_error(stmt)); + nrows = -1; + goto out; + } + if (rc == MYSQL_NO_DATA) + break; + + /* rc == 0 or rc == MYSQL_DATA_TRUNCATED */ + + ++nrows; + if (callback) + next_row = callback ((CcnetDBRow *)&row, data); + + for (i = 0; i < row.column_count; ++i) { + g_free (row.new_binds[i].buffer); + g_free (row.new_binds[i].length); + g_free (row.new_binds[i].is_null); + memset (&row.new_binds[i], 0, sizeof(MYSQL_BIND)); + } + + if (!next_row) break; } - if (error) { - ccnet_warning ("Error get next result from prep stmt: %s.\n", error->message); - g_clear_error (&error); - n_rows = -1; +out: + if (stmt) { + mysql_stmt_free_result (stmt); + mysql_stmt_close (stmt); + } + if (params) { + for (i = 0; i < n; ++i) { + g_free (params[i].buffer); + g_free (params[i].length); + } + g_free (params); + } + if (row.results) { + for (i = 0; i < row.column_count; ++i) { + g_free (row.results[i].buffer); + g_free (row.results[i].length); + g_free (row.results[i].is_null); + } + g_free (row.results); + } + if (row.new_binds) { + for (i = 0; i < row.column_count; ++i) { + g_free (row.new_binds[i].buffer); + g_free (row.new_binds[i].length); + g_free (row.new_binds[i].is_null); + } + g_free (row.new_binds); + } + return nrows; +} + +static int +mysql_db_row_get_column_count (CcnetDBRow *vrow) +{ + MySQLDBRow *row = (MySQLDBRow *)vrow; + return row->column_count; +} + +static const char * +mysql_db_row_get_column_string (CcnetDBRow *vrow, int i) +{ + MySQLDBRow *row = (MySQLDBRow *)vrow; + + if (*(row->results[i].is_null)) { + return NULL; } - return n_rows; + char *ret = NULL; + unsigned long real_length = *(row->results[i].length); + /* If column size is larger then allocated buffer size, re-allocate a new buffer + * and fetch the column directly. + */ + if (real_length > row->results[i].buffer_length) { + row->new_binds[i].buffer = g_malloc (real_length + 1); + row->new_binds[i].buffer_type = MYSQL_TYPE_STRING; + row->new_binds[i].buffer_length = real_length; + row->new_binds[i].length = g_new0 (unsigned long, 1); + row->new_binds[i].is_null = g_new0 (my_bool, 1); + if (mysql_stmt_fetch_column (row->stmt, &row->new_binds[i], i, 0) != 0) { + ccnet_warning ("Faield to fetch column: %s\n", mysql_stmt_error(row->stmt)); + return NULL; + } + + ret = row->new_binds[i].buffer; + } else { + ret = row->results[i].buffer; + } + ret[real_length] = 0; + + return ret; +} + +static int +mysql_db_row_get_column_int (CcnetDBRow *vrow, int idx) +{ + const char *str; + char *e; + int ret; + + str = mysql_db_row_get_column_string (vrow, idx); + if (!str) { + return 0; + } + + errno = 0; + ret = strtol (str, &e, 10); + if (errno || (e == str)) { + ccnet_warning ("Number conversion failed.\n"); + return -1; + } + + return ret; +} + +static gint64 +mysql_db_row_get_column_int64 (CcnetDBRow *vrow, int idx) +{ + const char *str; + char *e; + gint64 ret; + + str = mysql_db_row_get_column_string (vrow, idx); + if (!str) { + return 0; + } + + errno = 0; + ret = strtoll (str, &e, 10); + if (errno || (e == str)) { + ccnet_warning ("Number conversion failed.\n"); + return -1; + } + + return ret; +} + +#endif /* HAVE_MYSQL */ + +/* SQLite DB */ + +/* SQLite thread synchronization rountines. + * See https://www.sqlite.org/unlock_notify.html + */ + +typedef struct UnlockNotification { + int fired; + pthread_cond_t cond; + pthread_mutex_t mutex; +} UnlockNotification; + +static void +unlock_notify_cb(void **ap_arg, int n_arg) +{ + int i; + + for (i = 0; i < n_arg; i++) { + UnlockNotification *p = (UnlockNotification *)ap_arg[i]; + pthread_mutex_lock (&p->mutex); + p->fired = 1; + pthread_cond_signal (&p->cond); + pthread_mutex_unlock (&p->mutex); + } +} + +static int +wait_for_unlock_notify(sqlite3 *db) +{ + UnlockNotification un; + un.fired = 0; + pthread_mutex_init (&un.mutex, NULL); + pthread_cond_init (&un.cond, NULL); + + int rc = sqlite3_unlock_notify(db, unlock_notify_cb, (void *)&un); + + if (rc == SQLITE_OK) { + pthread_mutex_lock(&un.mutex); + if (!un.fired) + pthread_cond_wait (&un.cond, &un.mutex); + pthread_mutex_unlock(&un.mutex); + } + + pthread_cond_destroy (&un.cond); + pthread_mutex_destroy (&un.mutex); + + return rc; +} + +static int +sqlite3_blocking_step(sqlite3_stmt *stmt) +{ + int rc; + while (SQLITE_LOCKED == (rc = sqlite3_step(stmt))) { + rc = wait_for_unlock_notify(sqlite3_db_handle(stmt)); + if (rc != SQLITE_OK) + break; + sqlite3_reset(stmt); + } + return rc; +} + +static int +sqlite3_blocking_prepare_v2(sqlite3 *db, const char *sql, int sql_len, sqlite3_stmt **pstmt, const char **pz) +{ + int rc; + while (SQLITE_LOCKED == (rc = sqlite3_prepare_v2(db, sql, sql_len, pstmt, pz))) { + rc = wait_for_unlock_notify(db); + if (rc != SQLITE_OK) + break; + } + return rc; +} + +static int +sqlite3_blocking_exec(sqlite3 *db, const char *sql, int (*callback)(void *, int, char **, char **), void *arg, char **errmsg) +{ + int rc; + while (SQLITE_LOCKED == (rc = sqlite3_exec(db, sql, callback, arg, errmsg))) { + rc = wait_for_unlock_notify(db); + if (rc != SQLITE_OK) + break; + } + return rc; +} + +typedef struct SQLiteDB { + CcnetDB parent; + char *db_path; +} SQLiteDB; + +typedef struct SQLiteDBConnection { + DBConnection parent; + sqlite3 *db_conn; +} SQLiteDBConnection; + +static CcnetDB * +sqlite_db_new (const char *db_path) +{ + SQLiteDB *db = g_new0 (SQLiteDB, 1); + db->db_path = g_strdup(db_path); + + return (CcnetDB *)db; +} + +static DBConnection * +sqlite_db_get_connection (CcnetDB *vdb) +{ + SQLiteDB *db = (SQLiteDB *)vdb; + sqlite3 *db_conn; + int result; + const char *errmsg; + SQLiteDBConnection *conn; + + result = sqlite3_open_v2 (db->db_path, &db_conn, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_SHAREDCACHE, NULL); + if (result != SQLITE_OK) { + errmsg = sqlite3_errmsg(db_conn); + ccnet_warning ("Failed to open sqlite db: %s\n", errmsg ? errmsg : "no error given"); + return NULL; + } + + conn = g_new0 (SQLiteDBConnection, 1); + conn->db_conn = db_conn; + + return (DBConnection *)conn; +} + +static void +sqlite_db_release_connection (DBConnection *vconn) +{ + if (!vconn) + return; + + SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; + + sqlite3_close (conn->db_conn); + + g_free (conn); +} + +static int +sqlite_db_execute_sql_no_stmt (DBConnection *vconn, const char *sql) +{ + SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; + char *errmsg = NULL; + int rc; + + rc = sqlite3_blocking_exec (conn->db_conn, sql, NULL, NULL, &errmsg); + if (rc != SQLITE_OK) { + ccnet_warning ("sqlite3_exec failed %s: %s", sql, errmsg ? errmsg : "no error given"); + if (errmsg) + sqlite3_free (errmsg); + return -1; + } + + return 0; +} + +static int +_bind_parameters_sqlite (sqlite3 *db, sqlite3_stmt *stmt, int n, va_list args) +{ + int i; + const char *type; + + for (i = 0; i < n; ++i) { + type = va_arg (args, const char *); + if (strcmp(type, "int") == 0) { + int x = va_arg (args, int); + if (sqlite3_bind_int (stmt, i+1, x) != SQLITE_OK) { + ccnet_warning ("sqlite3_bind_int failed: %s\n", sqlite3_errmsg(db)); + return -1; + } + } else if (strcmp (type, "int64") == 0) { + gint64 x = va_arg (args, gint64); + if (sqlite3_bind_int64 (stmt, i+1, x) != SQLITE_OK) { + ccnet_warning ("sqlite3_bind_int64 failed: %s\n", sqlite3_errmsg(db)); + return -1; + } + } else if (strcmp (type, "string") == 0) { + const char *s = va_arg (args, const char *); + if (sqlite3_bind_text (stmt, i+1, s, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ccnet_warning ("sqlite3_bind_text failed: %s\n", sqlite3_errmsg(db)); + return -1; + } + } else { + ccnet_warning ("BUG: invalid prep stmt parameter type %s.\n", type); + g_return_val_if_reached (-1); + } + } + + return 0; +} + +static int +sqlite_db_execute_sql (DBConnection *vconn, const char *sql, int n, va_list args) +{ + SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; + sqlite3 *db = conn->db_conn; + sqlite3_stmt *stmt; + int rc; + int ret = 0; + + rc = sqlite3_blocking_prepare_v2 (db, sql, -1, &stmt, NULL); + if (rc != SQLITE_OK) { + ccnet_warning ("sqlite3_prepare_v2 failed %s: %s", sql, sqlite3_errmsg(db)); + return -1; + } + + if (_bind_parameters_sqlite (db, stmt, n, args) < 0) { + ccnet_warning ("Failed to bind parameters for sql %s\n", sql); + ret = -1; + goto out; + } + + rc = sqlite3_blocking_step (stmt); + if (rc != SQLITE_DONE) { + ccnet_warning ("sqlite3_step failed %s: %s", sql, sqlite3_errmsg(db)); + ret = -1; + goto out; + } + +out: + sqlite3_finalize (stmt); + return ret; +} + +typedef struct SQLiteDBRow { + CcnetDBRow parent; + int column_count; + sqlite3 *db; + sqlite3_stmt *stmt; +} SQLiteDBRow; + +static int +sqlite_db_query_foreach_row (DBConnection *vconn, const char *sql, + CcnetDBRowFunc callback, void *data, + int n, va_list args) +{ + SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; + sqlite3 *db = conn->db_conn; + sqlite3_stmt *stmt; + int rc; + int nrows = 0; + + rc = sqlite3_blocking_prepare_v2 (db, sql, -1, &stmt, NULL); + if (rc != SQLITE_OK) { + ccnet_warning ("sqlite3_prepare_v2 failed %s: %s", sql, sqlite3_errmsg(db)); + return -1; + } + + if (_bind_parameters_sqlite (db, stmt, n, args) < 0) { + ccnet_warning ("Failed to bind parameters for sql %s\n", sql); + nrows = -1; + goto out; + } + + SQLiteDBRow row; + memset (&row, 0, sizeof(row)); + row.db = db; + row.stmt = stmt; + row.column_count = sqlite3_column_count (stmt); + + while (1) { + rc = sqlite3_blocking_step (stmt); + if (rc == SQLITE_ROW) { + ++nrows; + if (callback && !callback ((CcnetDBRow *)&row, data)) + break; + } else if (rc == SQLITE_DONE) { + break; + } else { + ccnet_warning ("sqlite3_step failed %s: %s\n", sql, sqlite3_errmsg(db)); + nrows = -1; + goto out; + } + } + +out: + sqlite3_finalize (stmt); + return nrows; +} + +static int +sqlite_db_row_get_column_count (CcnetDBRow *vrow) +{ + SQLiteDBRow *row = (SQLiteDBRow *)vrow; + + return row->column_count; +} + +static const char * +sqlite_db_row_get_column_string (CcnetDBRow *vrow, int idx) +{ + SQLiteDBRow *row = (SQLiteDBRow *)vrow; + + return (const char *)sqlite3_column_text (row->stmt, idx); +} + +static int +sqlite_db_row_get_column_int (CcnetDBRow *vrow, int idx) +{ + SQLiteDBRow *row = (SQLiteDBRow *)vrow; + + return sqlite3_column_int (row->stmt, idx); +} + +static gint64 +sqlite_db_row_get_column_int64 (CcnetDBRow *vrow, int idx) +{ + SQLiteDBRow *row = (SQLiteDBRow *)vrow; + + return sqlite3_column_int64 (row->stmt, idx); } diff --git a/net/common/ccnet-db.h b/net/common/ccnet-db.h index 60749c6..c7e7a81 100644 --- a/net/common/ccnet-db.h +++ b/net/common/ccnet-db.h @@ -3,7 +3,6 @@ #define DB_SQLITE "sqlite" #define DB_MYSQL "mysql" -#define DB_PGSQL "pgsql" enum { CCNET_DB_TYPE_SQLITE, @@ -28,6 +27,7 @@ ccnet_db_new_mysql (const char *host, const char *charset, int max_connections); +#if 0 CcnetDB * ccnet_db_new_pgsql (const char *host, unsigned int port, @@ -36,13 +36,11 @@ ccnet_db_new_pgsql (const char *host, const char *db_name, const char *unix_socket, int max_connections); +#endif CcnetDB * ccnet_db_new_sqlite (const char *db_path); -void -ccnet_db_free (CcnetDB *db); - int ccnet_db_type (CcnetDB *db); @@ -102,21 +100,13 @@ ccnet_db_trans_foreach_selected_row (CcnetDBTrans *trans, const char *sql, CcnetDBRowFunc callback, void *data, int n, ...); -/* Escape a string contant by doubling '\" characters. - */ -char * -ccnet_db_escape_string (CcnetDB *db, const char *from); - -gboolean -pgsql_index_exists (CcnetDB *db, const char *index_name); - /* Prepared Statements */ int ccnet_db_statement_query (CcnetDB *db, const char *sql, int n, ...); gboolean -ccnet_db_statement_exists (CcnetDB *db, const char *sql, int n, ...); +ccnet_db_statement_exists (CcnetDB *db, const char *sql, gboolean *db_err, int n, ...); int ccnet_db_statement_foreach_row (CcnetDB *db, const char *sql, diff --git a/net/common/db-wrapper/Makefile.am b/net/common/db-wrapper/Makefile.am deleted file mode 100644 index f333eed..0000000 --- a/net/common/db-wrapper/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -AM_CFLAGS = -I$(top_srcdir)/net/common -I$(top_srcdir)/lib \ - -I$(top_srcdir)/include -I$(top_srcdir)/include/ccnet \ - -Wall @GLIB2_CFLAGS@ @MSVC_CFLAGS@ @MYSQL_CFLAGS@ @PGSQL_CFLAGS@ - -noinst_LTLIBRARIES = libdbwrapper.la - -noinst_HEADERS = db-wrapper.h mysql-db-ops.h sqlite-db-ops.h pgsql-db-ops.h - -if WITH_MYSQL - MYSQL_DB_SRC = mysql-db-ops.c -else - MYSQL_DB_SRC = -endif - -if WITH_POSTGRESQL - PGSQL_DB_SRC = pgsql-db-ops.c -else - PGSQL_DB_SRC = -endif - -libdbwrapper_la_SOURCES = db-wrapper.c sqlite-db-ops.c $(MYSQL_DB_SRC) $(PGSQL_DB_SRC) - -libdbwrapper_la_LDFLAGS = -Wl,-z -Wl,defs -libdbwrapper_la_LIBADD = @SSL_LIBS@ @GLIB2_LIBS@ @MYSQL_LIBS@ -lsqlite3 @PGSQL_LIBS@ diff --git a/net/common/db-wrapper/db-wrapper.c b/net/common/db-wrapper/db-wrapper.c deleted file mode 100644 index 7812c1b..0000000 --- a/net/common/db-wrapper/db-wrapper.c +++ /dev/null @@ -1,453 +0,0 @@ -#include "common.h" - -#include "db-wrapper.h" -#include "sqlite-db-ops.h" - -#ifdef HAVE_MYSQL -#include "mysql-db-ops.h" -#endif - -#ifdef HAVE_POSTGRESQL -#include "pgsql-db-ops.h" -#endif - -typedef struct DBOperations { - void (*db_conn_pool_free) (DBConnPool *); - DBConnection* (*get_db_connection) (DBConnPool *, GError **); - void (*db_connection_close) (DBConnection *); - gboolean (*db_connection_ping) (DBConnection *); - gboolean (*db_connection_execute) (DBConnection *, const char *, GError **); - ResultSet* (*db_connection_execute_query) (DBConnection *, const char *, GError **); - gboolean (*result_set_next) (ResultSet *, GError **); - const char* (*result_set_get_string) (ResultSet *, int, GError **); - void (*result_set_free) (ResultSet *); - int (*result_set_get_column_count) (ResultSet *); - DBStmt* (*db_connection_prepare_statement) (DBConnection *, const char *, GError **); - gboolean (*db_stmt_set_int) (DBStmt *, int, int, GError **); - gboolean (*db_stmt_set_int64) (DBStmt *, int, gint64, GError **); - gboolean (*db_stmt_set_string) (DBStmt *, int, const char *, GError **); - gboolean (*db_stmt_execute) (DBStmt *, GError **); - ResultSet* (*db_stmt_execute_query) (DBStmt *, GError **); - void (*db_stmt_free) (DBStmt *); - gboolean (*db_connection_begin_transaction) (DBConnection *, GError **); - gboolean (*db_connection_commit) (DBConnection *, GError **); - gboolean (*db_connection_rollback) (DBConnection *, GError **); -} DBOperations; - -static DBOperations db_ops; - -/* DB Connection Pool. */ - -static void -init_conn_pool_common (DBConnPool *pool, int max_connections) -{ - pool->connections = g_ptr_array_sized_new (max_connections); - pthread_mutex_init (&pool->lock, NULL); - pool->max_connections = max_connections; -} - -#ifdef HAVE_MYSQL - -DBConnPool * -db_conn_pool_new_mysql (const char *host, - const char *user, - const char *password, - unsigned int port, - const char *db_name, - const char *unix_socket, - gboolean use_ssl, - const char *charset, - int max_connections) -{ - db_ops.db_conn_pool_free = mysql_db_conn_pool_free; - db_ops.get_db_connection = mysql_get_db_connection; - db_ops.db_connection_close = mysql_db_connection_close; - db_ops.db_connection_ping = mysql_db_connection_ping; - db_ops.db_connection_execute = mysql_db_connection_execute; - db_ops.db_connection_execute_query = mysql_execute_query; - db_ops.result_set_next = mysql_result_set_next; - db_ops.result_set_get_string = mysql_result_set_get_string; - db_ops.result_set_free = mysql_result_set_free; - db_ops.result_set_get_column_count = mysql_result_set_get_column_count; - db_ops.db_connection_prepare_statement = mysql_prepare_statement; - db_ops.db_stmt_set_int = mysql_stmt_set_int; - db_ops.db_stmt_set_int64 = mysql_stmt_set_int64; - db_ops.db_stmt_set_string = mysql_stmt_set_string; - db_ops.db_stmt_execute = mysql_db_stmt_execute; - db_ops.db_stmt_execute_query = mysql_db_stmt_execute_query; - db_ops.db_stmt_free = mysql_db_stmt_free; - db_ops.db_connection_begin_transaction = mysql_db_begin_transaction; - db_ops.db_connection_commit = mysql_db_commit; - db_ops.db_connection_rollback = mysql_db_rollback; - - DBConnPool *pool; - - pool = mysql_db_conn_pool_new (host, user, password, port, db_name, unix_socket, - use_ssl, charset); - init_conn_pool_common (pool, max_connections); - - return pool; -} - -#endif - -#ifdef HAVE_POSTGRESQL - -DBConnPool * -db_conn_pool_new_pgsql (const char *host, - unsigned int port, - const char *user, - const char *password, - const char *db_name, - const char *unix_socket, - int max_connections) -{ - db_ops.db_conn_pool_free = pgsql_db_conn_pool_free; - db_ops.get_db_connection = pgsql_get_db_connection; - db_ops.db_connection_close = pgsql_db_connection_close; - db_ops.db_connection_ping = pgsql_db_connection_ping; - db_ops.db_connection_execute = pgsql_db_connection_execute; - db_ops.db_connection_execute_query = pgsql_execute_query; - db_ops.result_set_next = pgsql_result_set_next; - db_ops.result_set_get_string = pgsql_result_set_get_string; - db_ops.result_set_free = pgsql_result_set_free; - db_ops.result_set_get_column_count = pgsql_result_set_get_column_count; - db_ops.db_connection_prepare_statement = pgsql_prepare_statement; - db_ops.db_stmt_set_int = pgsql_stmt_set_int; - db_ops.db_stmt_set_int64 = pgsql_stmt_set_int64; - db_ops.db_stmt_set_string = pgsql_stmt_set_string; - db_ops.db_stmt_execute = pgsql_db_stmt_execute; - db_ops.db_stmt_execute_query = pgsql_db_stmt_execute_query; - db_ops.db_stmt_free = pgsql_db_stmt_free; - db_ops.db_connection_begin_transaction = pgsql_db_begin_transaction; - db_ops.db_connection_commit = pgsql_db_commit; - db_ops.db_connection_rollback = pgsql_db_rollback; - - DBConnPool *pool; - - pool = pgsql_db_conn_pool_new (host, port, user, password, db_name, unix_socket); - init_conn_pool_common (pool, max_connections); - - return pool; -} - -#endif - -DBConnPool * -db_conn_pool_new_sqlite (const char *db_path, int max_connections) -{ - db_ops.db_conn_pool_free = sqlite_db_conn_pool_free; - db_ops.get_db_connection = sqlite_get_db_connection; - db_ops.db_connection_close = sqlite_db_connection_close; - db_ops.db_connection_ping = sqlite_db_connection_ping; - db_ops.db_connection_execute = sqlite_db_connection_execute; - db_ops.db_connection_execute_query = sqlite_execute_query; - db_ops.result_set_next = sqlite_result_set_next; - db_ops.result_set_get_string = sqlite_result_set_get_string; - db_ops.result_set_free = sqlite_result_set_free; - db_ops.result_set_get_column_count = sqlite_result_set_get_column_count; - db_ops.db_connection_prepare_statement = sqlite_prepare_statement; - db_ops.db_stmt_set_int = sqlite_stmt_set_int; - db_ops.db_stmt_set_int64 = sqlite_stmt_set_int64; - db_ops.db_stmt_set_string = sqlite_stmt_set_string; - db_ops.db_stmt_execute = sqlite_db_stmt_execute; - db_ops.db_stmt_execute_query = sqlite_db_stmt_execute_query; - db_ops.db_stmt_free = sqlite_db_stmt_free; - db_ops.db_connection_begin_transaction = sqlite_db_begin_transaction; - db_ops.db_connection_commit = sqlite_db_commit; - db_ops.db_connection_rollback = sqlite_db_rollback; - - DBConnPool *pool; - - pool = sqlite_db_conn_pool_new (db_path); - init_conn_pool_common (pool, max_connections); - - return pool; -} - -void -db_conn_pool_free (DBConnPool *pool) -{ - g_ptr_array_free (pool->connections, TRUE); - pthread_mutex_destroy (&pool->lock); - - return db_ops.db_conn_pool_free (pool); -} - -/* DB Connections. */ - -DBConnection * -db_conn_pool_get_connection (DBConnPool *pool, GError **error) -{ - DBConnection *conn = NULL; - - pthread_mutex_lock (&pool->lock); - - guint i, size = pool->connections->len; - for (i = 0; i < size; ++i) { - conn = g_ptr_array_index (pool->connections, i); - if (conn->is_available && db_connection_ping (conn)) { - conn->is_available = FALSE; - goto out; - } - } - conn = NULL; - if (size < pool->max_connections) { - conn = db_ops.get_db_connection (pool, error); - if (conn) { - conn->is_available = FALSE; - conn->pool = pool; - g_ptr_array_add (pool->connections, conn); - } - } - -out: - pthread_mutex_unlock (&pool->lock); - return conn; -} - -static void -db_connection_clear (DBConnection *conn) -{ - result_set_free (conn->result_set); - db_stmt_free (conn->stmt); - conn->result_set = NULL; - conn->stmt = NULL; -} - -void -db_connection_close (DBConnection *conn) -{ - if (!conn) - return; - - if (conn->in_transaction) - db_connection_rollback (conn, NULL); - - db_connection_clear (conn); - - pthread_mutex_lock (&conn->pool->lock); - conn->is_available = TRUE; - pthread_mutex_unlock (&conn->pool->lock); -} - -gboolean -db_connection_execute (DBConnection *conn, const char *sql, GError **error) -{ - return db_ops.db_connection_execute (conn, sql, error); -} - -gboolean -db_connection_ping (DBConnection *conn) -{ - return db_ops.db_connection_ping (conn); -} - -/* Result Sets. */ - -void -result_set_free (ResultSet *r) -{ - if (!r) - return; - - return db_ops.result_set_free (r); -} - -ResultSet * -db_connection_execute_query (DBConnection *conn, const char *sql, GError **error) -{ - ResultSet *result_set; - - if (conn->result_set) { - result_set_free (conn->result_set); - conn->result_set = NULL; - } - - result_set = db_ops.db_connection_execute_query (conn, sql, error); - - if (result_set) - conn->result_set = result_set; - - return result_set; -} - -gboolean -result_set_next (ResultSet *r, GError **error) -{ - return db_ops.result_set_next (r, error); -} - -const char * -result_set_get_string (ResultSet *r, int idx, GError **error) -{ - return db_ops.result_set_get_string (r, idx, error); -} - -int -result_set_get_int (ResultSet *r, int idx, GError **error) -{ - const char *str; - char *e; - int ret; - - str = db_ops.result_set_get_string (r, idx, error); - if (*error) { - return -1; - } - - if (!str) { - return 0; - } - - errno = 0; - ret = strtol (str, &e, 10); - if (errno || (e == str)) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Number conversion failed."); - return -1; - } - - return ret; -} - -gint64 -result_set_get_int64 (ResultSet *r, int idx, GError **error) -{ - const char *str; - char *e; - gint64 ret; - - str = db_ops.result_set_get_string (r, idx, error); - if (*error) { - return -1; - } - - if (!str) { - return 0; - } - - errno = 0; - ret = strtoll (str, &e, 10); - if (errno || (e == str)) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Number conversion failed."); - return -1; - } - - return ret; -} - -int -result_set_get_column_count (ResultSet *r) -{ - return db_ops.result_set_get_column_count (r); -} - -/* Prepared Statements. */ - -DBStmt * -db_connection_prepare_statement (DBConnection *conn, const char *sql, GError **error) -{ - DBStmt *stmt; - - if (conn->stmt) { - db_stmt_free (conn->stmt); - conn->stmt = NULL; - } - - stmt = db_ops.db_connection_prepare_statement (conn, sql, error); - - if (stmt) - conn->stmt = stmt; - - return stmt; -} - -int -db_stmt_set_int (DBStmt *stmt, int idx, int x, GError **error) -{ - return db_ops.db_stmt_set_int (stmt, idx, x, error); -} - -int -db_stmt_set_int64 (DBStmt *stmt, int idx, gint64 x, GError **error) -{ - return db_ops.db_stmt_set_int64 (stmt, idx, x, error); -} - -int -db_stmt_set_string (DBStmt *stmt, int idx, const char *s, GError **error) -{ - return db_ops.db_stmt_set_string (stmt, idx, s, error); -} - -gboolean -db_stmt_execute (DBStmt *stmt, GError **error) -{ - return db_ops.db_stmt_execute (stmt, error); -} - -ResultSet * -db_stmt_execute_query (DBStmt *stmt, GError **error) -{ - ResultSet *result_set; - - if (stmt->result_set) { - result_set_free (stmt->result_set); - stmt->result_set = NULL; - } - - result_set = db_ops.db_stmt_execute_query (stmt, error); - - if (result_set) - stmt->result_set = result_set; - - return result_set; -} - -void -db_stmt_free (DBStmt *stmt) -{ - if (!stmt) - return; - - if (stmt->result_set) - result_set_free (stmt->result_set); - - return db_ops.db_stmt_free (stmt); -} - -/* Transactions. */ - -gboolean -db_connection_begin_transaction (DBConnection *conn, GError **error) -{ - gboolean ret; - - ret = db_ops.db_connection_begin_transaction (conn, error); - if (ret) - conn->in_transaction++; - - return ret; -} - -gboolean -db_connection_commit (DBConnection *conn, GError **error) -{ - if (conn->in_transaction) - conn->in_transaction = 0; - - return db_ops.db_connection_commit (conn, error); -} - -gboolean -db_connection_rollback (DBConnection *conn, GError **error) -{ - if (conn->in_transaction) { - db_connection_clear (conn); - conn->in_transaction = 0; - } - - return db_ops.db_connection_rollback (conn, error); -} diff --git a/net/common/db-wrapper/db-wrapper.h b/net/common/db-wrapper/db-wrapper.h deleted file mode 100644 index 2125af8..0000000 --- a/net/common/db-wrapper/db-wrapper.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef DB_WRAPPER_H -#define DB_WARPPER_H - -#include -#include - -#define SEAF_DB_ERROR_DOMAIN g_quark_from_string("SEAF_DB") -#define SEAF_DB_ERROR_CODE 0 - -/* DB Connection Pool. */ - -struct DBConnPool { - GPtrArray *connections; - pthread_mutex_t lock; - int max_connections; -}; -typedef struct DBConnPool DBConnPool; - -DBConnPool * -db_conn_pool_new_mysql (const char *host, - const char *user, - const char *password, - unsigned int port, - const char *db_name, - const char *unix_socket, - gboolean use_ssl, - const char *charset, - int max_connections); - -DBConnPool * -db_conn_pool_new_pgsql (const char *host, - unsigned int port, - const char *user, - const char *password, - const char *db_name, - const char *unix_socket, - int max_connections); - -DBConnPool * -db_conn_pool_new_sqlite (const char *db_path, int max_connections); - -void -db_conn_pool_free (DBConnPool *pool); - -/* DB Connections. */ - -struct ResultSet; -typedef struct ResultSet ResultSet; - -struct DBStmt; -typedef struct DBStmt DBStmt; - -struct DBConnection { - gboolean is_available; - int in_transaction; - DBConnPool *pool; - ResultSet *result_set; - DBStmt *stmt; -}; -typedef struct DBConnection DBConnection; - -DBConnection * -db_conn_pool_get_connection (DBConnPool *pool, GError **error); - -void -db_connection_close (DBConnection *conn); - -gboolean -db_connection_ping (DBConnection *conn); - -gboolean -db_connection_execute (DBConnection *conn, const char *sql, GError **error); - -/* Result Sets. */ - -struct ResultSet { - /* Empty */ -}; - -ResultSet * -db_connection_execute_query (DBConnection *conn, const char *sql, GError **error); - -gboolean -result_set_next (ResultSet *r, GError **error); - -const char * -result_set_get_string (ResultSet *r, int idx, GError **error); - -int -result_set_get_int (ResultSet *r, int idx, GError **error); - -gint64 -result_set_get_int64 (ResultSet *r, int idx, GError **error); - -int -result_set_get_column_count (ResultSet *r); - -void -result_set_free (ResultSet *r); - -/* Prepared Statements. */ - -struct DBStmt { - ResultSet *result_set; -}; - -DBStmt * -db_connection_prepare_statement (DBConnection *conn, const char *sql, GError **error); - -gboolean -db_stmt_set_int (DBStmt *stmt, int idx, int x, GError **error); - -gboolean -db_stmt_set_int64 (DBStmt *stmt, int idx, gint64 x, GError **error); - -gboolean -db_stmt_set_string (DBStmt *stmt, int idx, const char *s, GError **error); - -gboolean -db_stmt_execute (DBStmt *stmt, GError **error); - -ResultSet * -db_stmt_execute_query (DBStmt *stmt, GError **error); - -void -db_stmt_free (DBStmt *stmt); - -/* Transactions. */ - -gboolean -db_connection_begin_transaction (DBConnection *conn, GError **error); - -gboolean -db_connection_commit (DBConnection *conn, GError **error); - -gboolean -db_connection_rollback (DBConnection *conn, GError **error); - -#endif diff --git a/net/common/db-wrapper/mysql-db-ops.c b/net/common/db-wrapper/mysql-db-ops.c deleted file mode 100644 index a66324a..0000000 --- a/net/common/db-wrapper/mysql-db-ops.c +++ /dev/null @@ -1,585 +0,0 @@ -#include "common.h" - -#include "db-wrapper.h" -#include "mysql-db-ops.h" - -#include - -/* Connection Pool. */ - -typedef struct MySQLDBConnPool { - DBConnPool parent; - char *host; - char *user; - char *password; - unsigned int port; - char *db_name; - char *unix_socket; - gboolean use_ssl; - char *charset; -} MySQLDBConnPool; - -DBConnPool * -mysql_db_conn_pool_new (const char *host, - const char *user, - const char *password, - unsigned int port, - const char *db_name, - const char *unix_socket, - gboolean use_ssl, - const char *charset) -{ - MySQLDBConnPool *pool = g_new0 (MySQLDBConnPool, 1); - - pool->host = g_strdup (host); - pool->user = g_strdup (user); - pool->password = g_strdup (password); - pool->port = port; - pool->db_name = g_strdup(db_name); - pool->unix_socket = g_strdup(unix_socket); - pool->use_ssl = use_ssl; - pool->charset = g_strdup(charset); - - mysql_library_init (0, NULL, NULL); - - return (DBConnPool *)pool; -} - -void -mysql_db_conn_pool_free (DBConnPool *vpool) -{ - MySQLDBConnPool *pool = (MySQLDBConnPool *)vpool; - - g_free (pool->host); - g_free (pool->user); - g_free (pool->password); - g_free (pool->db_name); - g_free (pool->unix_socket); - g_free (pool->charset); - - g_free (pool); -} - -/* Connection. */ - -typedef struct MySQLDBConnection { - DBConnection parent; - MYSQL *db; -} MySQLDBConnection; - -#define SQL_DEFAULT_TCP_TIMEOUT 3 - -static MYSQL * -connect_mysql (MySQLDBConnPool *pool, GError **error) -{ - my_bool yes = 1; - volatile int connect_timeout = SQL_DEFAULT_TCP_TIMEOUT; - unsigned long client_flags = CLIENT_MULTI_STATEMENTS; - MYSQL *db; - - db = mysql_init (NULL); - if (!db) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Failed to allocate mysql handle."); - return NULL; - } - - if (pool->use_ssl) - mysql_ssl_set(db, 0,0,0,0,0); - - if (pool->charset) - mysql_options(db, MYSQL_SET_CHARSET_NAME, pool->charset); - - mysql_options(db, MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&connect_timeout); - mysql_options(db, MYSQL_OPT_RECONNECT, (const char*)&yes); - - if (mysql_real_connect(db, pool->host, pool->user, pool->password, - pool->db_name, pool->port, - pool->unix_socket, client_flags)) { - return db; - } else { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Failed to connect to MySQL: %s", mysql_error(db)); - mysql_close (db); - return NULL; - } -} - -DBConnection * -mysql_get_db_connection (DBConnPool *vpool, GError **error) -{ - MySQLDBConnPool *pool = (MySQLDBConnPool *)vpool; - MySQLDBConnection *conn; - MYSQL *db = connect_mysql (pool, error); - if (!db) - return NULL; - conn = g_new0 (MySQLDBConnection, 1); - conn->db = db; - return (DBConnection *)conn; -} - -void -mysql_db_connection_close (DBConnection *vconn) -{ - if (!vconn) - return; - - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - - mysql_close (conn->db); - - g_free (conn); -} - -gboolean -mysql_db_connection_ping (DBConnection *vconn) -{ - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - - return (mysql_ping (conn->db) == 0); -} - -gboolean -mysql_db_connection_execute (DBConnection *vconn, const char *sql, GError **error) -{ - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - - int rc = mysql_real_query (conn->db, sql, strlen(sql)); - if (rc != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "MySQL failed to execute: %s", mysql_error(conn->db)); - return FALSE; - } - return TRUE; -} - -/* Result Set. */ - -#define DEFAULT_COLUMN_SIZE 256 - -typedef struct MySQLResultSet { - ResultSet parent; - MYSQL_STMT *stmt; - int column_count; - MYSQL_BIND *bind; - int need_rebind; -} MySQLResultSet; - -void -mysql_result_set_free (ResultSet *vr) -{ - if (!vr) - return; - - MySQLResultSet *r = (MySQLResultSet *)vr; - - mysql_stmt_free_result (r->stmt); - mysql_stmt_close (r->stmt); - - int i; - for (i = 0; i < r->column_count; ++i) { - g_free (r->bind[i].buffer); - g_free (r->bind[i].length); - g_free (r->bind[i].is_null); - } - g_free (r->bind); - g_free (r); -} - -static MySQLResultSet * -mysql_result_set_new (MYSQL_STMT *stmt, GError **error) -{ - MySQLResultSet *r = g_new0 (MySQLResultSet, 1); - int i; - - r->stmt = stmt; - r->column_count = mysql_stmt_field_count (stmt); - r->bind = g_new0 (MYSQL_BIND, r->column_count); - for (i = 0; i < r->column_count; ++i) { - r->bind[i].buffer = g_malloc (DEFAULT_COLUMN_SIZE + 1); - r->bind[i].buffer_type = MYSQL_TYPE_STRING; - r->bind[i].buffer_length = DEFAULT_COLUMN_SIZE; - r->bind[i].length = g_new0 (unsigned long, 1); - r->bind[i].is_null = g_new0 (my_bool, 1); - } - - if (mysql_stmt_bind_result (stmt, r->bind) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_bind_result failed: %s\n", mysql_stmt_error(stmt)); - mysql_result_set_free ((ResultSet*)r); - return NULL; - } - - return r; -} - -static MYSQL_STMT * -prepare (MYSQL *db, const char *sql, GError **error) -{ - MYSQL_STMT *stmt; - - stmt = mysql_stmt_init (db); - if (!stmt) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_init out of memory"); - return NULL; - } - - if (mysql_stmt_prepare (stmt, sql, strlen(sql)) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_prepare failed: %s", - mysql_stmt_error(stmt)); - mysql_stmt_close (stmt); - return NULL; - } - - return stmt; -} - -ResultSet * -mysql_execute_query (DBConnection *vconn, const char *sql, GError **error) -{ - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - MYSQL_STMT *stmt; - MySQLResultSet *r; - - stmt = prepare (conn->db, sql, error); - if (!stmt) { - return NULL; - } - - unsigned long cursor = CURSOR_TYPE_READ_ONLY; - mysql_stmt_attr_set (stmt, STMT_ATTR_CURSOR_TYPE, &cursor); - - if (mysql_stmt_execute (stmt) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_execute failed: %s", - mysql_stmt_error(stmt)); - mysql_stmt_close (stmt); - return NULL; - } - - r = mysql_result_set_new (stmt, error); - if (!r) { - mysql_stmt_close (stmt); - return NULL; - } - - return (ResultSet *)r; -} - -static gboolean -check_mysql_column_size (MySQLResultSet *r, int i, GError **error) -{ - unsigned long real_length = *(r->bind[i].length); - - if ((real_length > r->bind[i].buffer_length)) { - /* Column was truncated, resize and fetch column directly. */ - g_free (r->bind[i].buffer); - r->bind[i].buffer = g_malloc (real_length + 1); - r->bind[i].buffer_length = real_length; - if (mysql_stmt_fetch_column (r->stmt, &r->bind[i], i, 0) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_fetch_column failed: %s", - mysql_stmt_error(r->stmt)); - return FALSE; - } - r->need_rebind = TRUE; - } - - return TRUE; -} - -gboolean -mysql_result_set_next (ResultSet *vr, GError **error) -{ - MySQLResultSet *r = (MySQLResultSet *)vr; - - if (r->need_rebind) { - if (mysql_stmt_bind_result (r->stmt, r->bind) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_bind_result failed: %s", - mysql_stmt_error(r->stmt)); - return FALSE; - } - r->need_rebind = FALSE; - } - - int rc = mysql_stmt_fetch (r->stmt); - if (rc == 1) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_fetch failed: %s", mysql_stmt_error(r->stmt)); - return FALSE; - } - return ((rc == 0) || (rc == MYSQL_DATA_TRUNCATED)); -} - -const char * -mysql_result_set_get_string (ResultSet *vr, int i, GError **error) -{ - MySQLResultSet *r = (MySQLResultSet *)vr; - char *ret; - - if (i < 0 || i >= r->column_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return NULL; - } - - if (*(r->bind[i].is_null)) { - return NULL; - } - - if (!check_mysql_column_size (r, i, error)) { - return NULL; - } - - ret = r->bind[i].buffer; - ret[r->bind[i].buffer_length] = 0; - return ret; -} - -int -mysql_result_set_get_column_count (ResultSet *vr) -{ - MySQLResultSet *r = (MySQLResultSet *)vr; - - return r->column_count; -} - -typedef struct MySQLDBStmt { - DBStmt parent; - int param_count; - MYSQL_STMT *stmt; - MYSQL_BIND *bind; -} MySQLDBStmt; - -static MySQLDBStmt * -mysql_stmt_new (MYSQL_STMT *stmt) -{ - MySQLDBStmt *p = g_new0 (MySQLDBStmt, 1); - - p->stmt = stmt; - p->param_count = (int)mysql_stmt_param_count(stmt); - if (p->param_count>0) { - p->bind = g_new0 (MYSQL_BIND, p->param_count); - } - - return p; -} - -DBStmt * -mysql_prepare_statement (DBConnection *vconn, const char *sql, GError **error) -{ - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - MYSQL_STMT *stmt; - MySQLDBStmt *ret; - - stmt = prepare (conn->db, sql, error); - if (!stmt) { - return NULL; - } - - ret = mysql_stmt_new (stmt); - - return (DBStmt*)ret; -} - -gboolean -mysql_stmt_set_int (DBStmt *vstmt, int i, int x, GError **error) -{ - MySQLDBStmt *stmt = (MySQLDBStmt *)vstmt; - int *pval; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - pval = g_new (int, 1); - *pval = x; - - stmt->bind[i].buffer_type = MYSQL_TYPE_LONG; - stmt->bind[i].buffer = (char *)pval; - stmt->bind[i].is_null = 0; - - return TRUE; -} - -gboolean -mysql_stmt_set_int64 (DBStmt *vstmt, int i, gint64 x, GError **error) -{ - MySQLDBStmt *stmt = (MySQLDBStmt *)vstmt; - gint64 *pval; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - pval = g_new (gint64, 1); - *pval = x; - - stmt->bind[i].buffer_type = MYSQL_TYPE_LONGLONG; - stmt->bind[i].buffer = (char *)pval; - stmt->bind[i].is_null = 0; - - return TRUE; -} - -gboolean -mysql_stmt_set_string (DBStmt *vstmt, int i, const char *s, GError **error) -{ - MySQLDBStmt *stmt = (MySQLDBStmt *)vstmt; - static my_bool yes = TRUE; - unsigned long *plen; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - stmt->bind[i].buffer_type = MYSQL_TYPE_STRING; - stmt->bind[i].buffer = g_strdup(s); - plen = g_new (unsigned long, 1); - stmt->bind[i].length = plen; - if (!s) { - *plen = 0; - stmt->bind[i].is_null = &yes; - } else { - *plen = strlen(s); - stmt->bind[i].is_null = 0; - } - - return TRUE; -} - -gboolean -mysql_db_stmt_execute (DBStmt *vstmt, GError **error) -{ - MySQLDBStmt *stmt = (MySQLDBStmt *)vstmt; - - if (stmt->param_count > 0 && - mysql_stmt_bind_param (stmt->stmt, stmt->bind) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_bind_param failed: %s", - mysql_stmt_error(stmt->stmt)); - return FALSE; - } - - unsigned long cursor = CURSOR_TYPE_NO_CURSOR; - mysql_stmt_attr_set (stmt->stmt, STMT_ATTR_CURSOR_TYPE, &cursor); - - if (mysql_stmt_execute (stmt->stmt) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_execute failed: %s", mysql_stmt_error(stmt->stmt)); - return FALSE; - } - - mysql_stmt_reset (stmt->stmt); - - return TRUE; -} - -ResultSet * -mysql_db_stmt_execute_query (DBStmt *vstmt, GError **error) -{ - MySQLDBStmt *stmt = (MySQLDBStmt *)vstmt; - - if (stmt->param_count > 0 && - mysql_stmt_bind_param (stmt->stmt, stmt->bind) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_bind_param failed: %s", - mysql_stmt_error(stmt->stmt)); - return NULL; - } - - unsigned long cursor = CURSOR_TYPE_READ_ONLY; - mysql_stmt_attr_set (stmt->stmt, STMT_ATTR_CURSOR_TYPE, &cursor); - - if (mysql_stmt_execute (stmt->stmt) != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "mysql_stmt_execute failed: %s", mysql_stmt_error(stmt->stmt)); - return NULL; - } - - MySQLResultSet *r = mysql_result_set_new (stmt->stmt, error); - if (*error) { - return NULL; - } - - return (ResultSet *)r; -} - -void -mysql_db_stmt_free (DBStmt *vstmt) -{ - if (!vstmt) - return; - - MySQLDBStmt *stmt = (MySQLDBStmt *)vstmt; - - /* If there is a result set associated with this stmt, the mysql stmt - * will be freed when freeing the result set. - */ - if (!stmt->parent.result_set) { - mysql_stmt_free_result (stmt->stmt); - mysql_stmt_close (stmt->stmt); - } - - int i; - for (i = 0; i < stmt->param_count; ++i) { - g_free (stmt->bind[i].buffer); - g_free (stmt->bind[i].length); - } - g_free (stmt->bind); - - g_free (stmt); -} - -/* Transaction. */ - -gboolean -mysql_db_begin_transaction (DBConnection *vconn, GError **error) -{ - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - - int rc = mysql_query (conn->db, "START TRANSACTION;"); - if (rc != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Failed to begin transaction: %s", mysql_error(conn->db)); - } - - return (rc == 0); -} - -gboolean -mysql_db_commit (DBConnection *vconn, GError **error) -{ - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - - int rc = mysql_query (conn->db, "COMMIT;"); - if (rc != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Failed to commit transaction: %s", mysql_error(conn->db)); - } - - return (rc == 0); -} - -gboolean -mysql_db_rollback (DBConnection *vconn, GError **error) -{ - MySQLDBConnection *conn = (MySQLDBConnection *)vconn; - - int rc = mysql_query (conn->db, "ROLLBACK;"); - if (rc != 0) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Failed to rollback transaction: %s", mysql_error(conn->db)); - } - - return (rc == 0); -} diff --git a/net/common/db-wrapper/mysql-db-ops.h b/net/common/db-wrapper/mysql-db-ops.h deleted file mode 100644 index 8c70f52..0000000 --- a/net/common/db-wrapper/mysql-db-ops.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef MYSQL_DB_OPS_H -#define MYSQL_DB_OPS_H - -DBConnPool * -mysql_db_conn_pool_new (const char *host, - const char *user, - const char *password, - unsigned int port, - const char *db_name, - const char *unix_socket, - gboolean use_ssl, - const char *charset); - -void -mysql_db_conn_pool_free (DBConnPool *vpool); - -DBConnection * -mysql_get_db_connection (DBConnPool *vpool, GError **error); - -void -mysql_db_connection_close (DBConnection *vconn); - -gboolean -mysql_db_connection_ping (DBConnection *vconn); - -gboolean -mysql_db_connection_execute (DBConnection *vconn, const char *sql, GError **error); - -void -mysql_result_set_free (ResultSet *vr); - -ResultSet * -mysql_execute_query (DBConnection *vconn, const char *sql, GError **error); - -gboolean -mysql_result_set_next (ResultSet *vr, GError **error); - -const char * -mysql_result_set_get_string (ResultSet *vr, int i, GError **error); - -int -mysql_result_set_get_column_count (ResultSet *vr); - -DBStmt * -mysql_prepare_statement (DBConnection *vconn, const char *sql, GError **error); - -gboolean -mysql_stmt_set_int (DBStmt *vstmt, int i, int x, GError **error); - -gboolean -mysql_stmt_set_int64 (DBStmt *vstmt, int i, gint64 x, GError **error); - -gboolean -mysql_stmt_set_string (DBStmt *vstmt, int i, const char *s, GError **error); - -gboolean -mysql_db_stmt_execute (DBStmt *vstmt, GError **error); - -ResultSet * -mysql_db_stmt_execute_query (DBStmt *vstmt, GError **error); - -void -mysql_db_stmt_free (DBStmt *vstmt); - -gboolean -mysql_db_begin_transaction (DBConnection *vconn, GError **error); - -gboolean -mysql_db_commit (DBConnection *vconn, GError **error); - -gboolean -mysql_db_rollback (DBConnection *vconn, GError **error); - -#endif diff --git a/net/common/db-wrapper/pgsql-db-ops.c b/net/common/db-wrapper/pgsql-db-ops.c deleted file mode 100644 index 4521f52..0000000 --- a/net/common/db-wrapper/pgsql-db-ops.c +++ /dev/null @@ -1,492 +0,0 @@ -#include "common.h" - -#include "db-wrapper.h" -#include "pgsql-db-ops.h" - -#include - -typedef struct PGDBConnPool { - DBConnPool parent; - char *host; - unsigned int port; - char *user; - char *password; - char *db_name; - char *unix_socket; -} PGDBConnPool; - -DBConnPool * -pgsql_db_conn_pool_new (const char *host, - unsigned int port, - const char *user, - const char *password, - const char *db_name, - const char *unix_socket) -{ - PGDBConnPool *pool = g_new0 (PGDBConnPool, 1); - - pool->host = g_strdup (host); - pool->port = port; - pool->user = g_strdup (user); - pool->password = g_strdup (password); - pool->db_name = g_strdup(db_name); - pool->unix_socket = g_strdup(unix_socket); - - return (DBConnPool *)pool; -} - -void -pgsql_db_conn_pool_free (DBConnPool *vpool) -{ - PGDBConnPool *pool = (PGDBConnPool *)vpool; - - g_free (pool->host); - g_free (pool->user); - g_free (pool->password); - g_free (pool->db_name); - g_free (pool->unix_socket); - - g_free (pool); -} - -typedef struct PGDBConnection { - DBConnection parent; - PGconn *db; -} PGDBConnection; - -static char * -escape_string_pgsql_connect (const char *str) -{ - GString *buf = g_string_new (NULL); - const char *p; - - for (p = str; *p != '\0'; ++p) { - if (*p == '\'' || *p == '\\') { - g_string_append_c (buf, '\\'); - g_string_append_c (buf, *p); - } else { - g_string_append_c (buf, *p); - } - } - - return g_string_free (buf, FALSE); -} - -static PGconn * -connect_pgsql (PGDBConnPool *pool, GError **error) -{ - GString *buf = g_string_new(""); - char *esc_password = NULL; - PGconn *db; - - g_string_append_printf (buf, "user='%s' ", pool->user); - - esc_password = escape_string_pgsql_connect (pool->password); - g_string_append_printf (buf, "password='%s' ", esc_password); - g_free (esc_password); - - if (pool->unix_socket) { - g_string_append_printf (buf, "host='%s' ", pool->unix_socket); - } else { - g_string_append_printf (buf, "host='%s' ", pool->host); - } - - if (pool->port > 0) { - g_string_append_printf (buf, "port=%u ", pool->port); - } - - g_string_append_printf (buf, "dbname='%s' ", pool->db_name); - - db = PQconnectdb (buf->str); - if (PQstatus (db) != CONNECTION_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "PQconnectdb failed: %s", PQerrorMessage (db)); - PQfinish (db); - db = NULL; - } - - g_string_free (buf, TRUE); - return db; -} - -DBConnection * -pgsql_get_db_connection (DBConnPool *vpool, GError **error) -{ - PGDBConnPool *pool = (PGDBConnPool *)vpool; - PGDBConnection *conn; - - PGconn *db = connect_pgsql (pool, error); - if (!db) - return NULL; - - conn = g_new0 (PGDBConnection, 1); - conn->db = db; - - return (DBConnection *)conn; -} - -void -pgsql_db_connection_close (DBConnection *vconn) -{ - if (!vconn) - return; - - PGDBConnection *conn = (PGDBConnection *)vconn; - - PQfinish (conn->db); - - g_free (conn); -} - -gboolean -pgsql_db_connection_ping (DBConnection *vconn) -{ - PGDBConnection *conn = (PGDBConnection *)vconn; - - return (PQstatus(conn->db) == CONNECTION_OK); -} - -gboolean -pgsql_db_connection_execute (DBConnection *vconn, const char *sql, GError **error) -{ - PGDBConnection *conn = (PGDBConnection *)vconn; - PGresult *res; - gboolean ret = TRUE; - - res = PQexec (conn->db, sql); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "PQexec failed: %s", PQresultErrorMessage(res)); - ret = FALSE; - } - PQclear (res); - - return ret; -} - -typedef struct PGResultSet { - ResultSet parent; - PGresult *res; - int curr_row; - int column_count; - int row_count; -} PGResultSet; - -void -pgsql_result_set_free (ResultSet *vr) -{ - if (!vr) - return; - - PGResultSet *r = (PGResultSet *)vr; - - PQclear (r->res); - g_free (r); -} - -static PGResultSet * -pgsql_result_set_new (PGresult *res) -{ - PGResultSet *r; - - r = g_new0 (PGResultSet, 1); - r->curr_row = -1; - r->column_count = PQnfields(res); - r->row_count = PQntuples(res); - r->res = res; - - return r; -} - -ResultSet * -pgsql_execute_query (DBConnection *vconn, const char *sql, GError **error) -{ - PGDBConnection *conn = (PGDBConnection *)vconn; - PGresult *res; - PGResultSet *r; - - res = PQexec (conn->db, sql); - if (PQresultStatus(res) != PGRES_TUPLES_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "PQexec failed: %s", PQresultErrorMessage(res)); - return NULL; - } - - r = pgsql_result_set_new (res); - - return (ResultSet *)r; -} - -gboolean -pgsql_result_set_next (ResultSet *vr, GError **error) -{ - PGResultSet *r = (PGResultSet *)vr; - - return ((r->curr_row)++ < (r->row_count - 1)); -} - -const char * -pgsql_result_set_get_string (ResultSet *vr, int i, GError **error) -{ - PGResultSet *r = (PGResultSet *)vr; - - if (PQgetisnull(r->res, r->curr_row, i)) - return NULL; - return PQgetvalue(r->res, r->curr_row, i); -} - -int -pgsql_result_set_get_column_count (ResultSet *vr) -{ - PGResultSet *r = (PGResultSet *)vr; - return r->column_count; -} - -typedef struct PGDBStmt { - DBStmt parent; - char *name; - PGconn *db; - int param_count; - char **values; - int *lengths; - int *formats; -} PGDBStmt; - -static PGDBStmt * -pgsql_stmt_new (PGconn *db, char *name, int param_count) -{ - PGDBStmt *stmt = g_new0 (PGDBStmt, 1); - - stmt->name = g_strdup(name); - stmt->db = db; - stmt->param_count = param_count; - - if (stmt->param_count) { - stmt->values = g_new0 (char *, param_count); - stmt->lengths = g_new0 (int, param_count); - stmt->formats = g_new0 (int, param_count); - } - - return stmt; -} - -/* Convert '?' in the query string to $1, $2, etc. */ -static char * -pgsql_format_query_string (const char *sql, int *param_count) -{ - GString *buf = g_string_new (NULL); - const char *p; - int i = 0; - - for (p = sql; *p != '\0'; ++p) { - if (*p == '?') { - ++i; - g_string_append_c (buf, '$'); - g_string_append_printf (buf, "%d", i); - } else { - g_string_append_c (buf, *p); - } - } - - *param_count = i; - - return g_string_free (buf, FALSE); -} - -static gint stmt_id = 0; - -DBStmt * -pgsql_prepare_statement (DBConnection *vconn, const char *sql, GError **error) -{ - PGDBConnection *conn = (PGDBConnection *)vconn; - char *query; - int param_count; - char *name; - PGresult *res; - PGDBStmt *stmt = NULL; - - query = pgsql_format_query_string (sql, ¶m_count); - - g_atomic_int_inc (&stmt_id); - name = g_strdup_printf ("%d", stmt_id); - - res = PQprepare (conn->db, name, query, 0, NULL); - ExecStatusType status = PQresultStatus(res); - if (res && (status == PGRES_EMPTY_QUERY || status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK)) { - stmt = pgsql_stmt_new (conn->db, name, param_count); - } else { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "PQprepare failed: %s", PQresultErrorMessage(res)); - } - - PQclear (res); - g_free (name); - g_free (query); - return (DBStmt *)stmt; -} - -gboolean -pgsql_stmt_set_int (DBStmt *vstmt, int i, int x, GError **error) -{ - PGDBStmt *stmt = (PGDBStmt *)vstmt; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - stmt->values[i] = g_strdup_printf("%d", x); - stmt->lengths[i] = 0; - stmt->formats[i] = 0; - - return TRUE; -} - -gboolean -pgsql_stmt_set_int64 (DBStmt *vstmt, int i, gint64 x, GError **error) -{ - PGDBStmt *stmt = (PGDBStmt *)vstmt; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - stmt->values[i] = g_strdup_printf("%"G_GINT64_FORMAT, x); - stmt->lengths[i] = 0; - stmt->formats[i] = 0; - - return TRUE; -} - -gboolean -pgsql_stmt_set_string (DBStmt *vstmt, int i, const char *s, GError **error) -{ - PGDBStmt *stmt = (PGDBStmt *)vstmt; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - stmt->values[i] = g_strdup(s); - stmt->lengths[i] = 0; - stmt->formats[i] = 0; - - return TRUE; -} - -gboolean -pgsql_db_stmt_execute (DBStmt *vstmt, GError **error) -{ - PGDBStmt *stmt = (PGDBStmt *)vstmt; - PGresult *res; - gboolean ret; - - res = PQexecPrepared (stmt->db, stmt->name, stmt->param_count, - (const char **)stmt->values, stmt->lengths, stmt->formats, 0); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "PGexecPrepared failed: %s", PQresultErrorMessage(res)); - ret = FALSE; - } - - ret = TRUE; - - PQclear(res); - - return ret; -} - -ResultSet * -pgsql_db_stmt_execute_query (DBStmt *vstmt, GError **error) -{ - PGDBStmt *stmt = (PGDBStmt *)vstmt; - PGresult *res; - PGResultSet *ret = NULL; - - res = PQexecPrepared (stmt->db, stmt->name, stmt->param_count, - (const char **)stmt->values, stmt->lengths, stmt->formats, 0); - if (PQresultStatus(res) != PGRES_TUPLES_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "PGexecPrepared failed: %s", PQresultErrorMessage(res)); - } - - ret = pgsql_result_set_new (res); - - return (ResultSet *)ret; -} - -void -pgsql_db_stmt_free (DBStmt *vstmt) -{ - if (!vstmt) - return; - - char Stmt[256]; - PGDBStmt *stmt = (PGDBStmt *)vstmt; - snprintf(Stmt, sizeof(Stmt), "DEALLOCATE \"%s\";", stmt->name); - PQclear(PQexec(stmt->db, Stmt)); - - g_free (stmt->name); - - int i; - for (i = 0; i < stmt->param_count; ++i) - g_free (stmt->values[i]); - g_free (stmt->values); - - g_free (stmt->lengths); - g_free (stmt->formats); - g_free (stmt); -} - -gboolean -pgsql_db_begin_transaction (DBConnection *vconn, GError **error) -{ - PGDBConnection *conn = (PGDBConnection *)vconn; - gboolean ret = TRUE; - - PGresult *res = PQexec(conn->db, "BEGIN TRANSACTION;"); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Begin transaction failed: %s", PQresultErrorMessage(res)); - ret = FALSE; - } - PQclear(res); - return ret; -} - -gboolean -pgsql_db_commit (DBConnection *vconn, GError **error) -{ - PGDBConnection *conn = (PGDBConnection *)vconn; - gboolean ret = TRUE; - - PGresult *res = PQexec(conn->db, "COMMIT TRANSACTION;"); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Commit transaction failed: %s", PQresultErrorMessage(res)); - ret = FALSE; - } - PQclear(res); - return ret; -} - -gboolean -pgsql_db_rollback (DBConnection *vconn, GError **error) -{ - PGDBConnection *conn = (PGDBConnection *)vconn; - gboolean ret = TRUE; - - PGresult *res = PQexec(conn->db, "ROLLBACK TRANSACTION;"); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Rollback transaction failed: %s", PQresultErrorMessage(res)); - ret = FALSE; - } - PQclear(res); - return ret; -} diff --git a/net/common/db-wrapper/pgsql-db-ops.h b/net/common/db-wrapper/pgsql-db-ops.h deleted file mode 100644 index f027aec..0000000 --- a/net/common/db-wrapper/pgsql-db-ops.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef PGSQL_DB_OPS_H -#define PGSQL_DB_OPS_H - -DBConnPool * -pgsql_db_conn_pool_new (const char *host, - unsigned int port, - const char *user, - const char *password, - const char *db_name, - const char *unix_socket); - -void -pgsql_db_conn_pool_free (DBConnPool *vpool); - -DBConnection * -pgsql_get_db_connection (DBConnPool *vpool, GError **error); - -void -pgsql_db_connection_close (DBConnection *vconn); - -gboolean -pgsql_db_connection_ping (DBConnection *vconn); - -gboolean -pgsql_db_connection_execute (DBConnection *vconn, const char *sql, GError **error); - -void -pgsql_result_set_free (ResultSet *vr); - -ResultSet * -pgsql_execute_query (DBConnection *vconn, const char *sql, GError **error); - -gboolean -pgsql_result_set_next (ResultSet *vr, GError **error); - -const char * -pgsql_result_set_get_string (ResultSet *vr, int i, GError **error); - -int -pgsql_result_set_get_column_count (ResultSet *vr); - -DBStmt * -pgsql_prepare_statement (DBConnection *vconn, const char *sql, GError **error); - -gboolean -pgsql_stmt_set_int (DBStmt *vstmt, int i, int x, GError **error); - -gboolean -pgsql_stmt_set_int64 (DBStmt *vstmt, int i, gint64 x, GError **error); - -gboolean -pgsql_stmt_set_string (DBStmt *vstmt, int i, const char *s, GError **error); - -gboolean -pgsql_db_stmt_execute (DBStmt *vstmt, GError **error); - -ResultSet * -pgsql_db_stmt_execute_query (DBStmt *vstmt, GError **error); - -void -pgsql_db_stmt_free (DBStmt *vstmt); - -gboolean -pgsql_db_begin_transaction (DBConnection *vconn, GError **error); - -gboolean -pgsql_db_commit (DBConnection *vconn, GError **error); - -gboolean -pgsql_db_rollback (DBConnection *vconn, GError **error); - -#endif diff --git a/net/common/db-wrapper/sqlite-db-ops.c b/net/common/db-wrapper/sqlite-db-ops.c deleted file mode 100644 index 87b7c55..0000000 --- a/net/common/db-wrapper/sqlite-db-ops.c +++ /dev/null @@ -1,477 +0,0 @@ -#include "common.h" - -#include "db-wrapper.h" -#include "sqlite-db-ops.h" - -#include -#include - -/* SQLite thread synchronization rountines. */ - -typedef struct UnlockNotification { - int fired; - pthread_cond_t cond; - pthread_mutex_t mutex; -} UnlockNotification; - -static void -unlock_notify_cb(void **ap_arg, int n_arg) -{ - int i; - - for (i = 0; i < n_arg; i++) { - UnlockNotification *p = (UnlockNotification *)ap_arg[i]; - pthread_mutex_lock (&p->mutex); - p->fired = 1; - pthread_cond_signal (&p->cond); - pthread_mutex_unlock (&p->mutex); - } -} - -static int -wait_for_unlock_notify(sqlite3 *db) -{ - UnlockNotification un; - un.fired = 0; - pthread_mutex_init (&un.mutex, NULL); - pthread_cond_init (&un.cond, NULL); - - int rc = sqlite3_unlock_notify(db, unlock_notify_cb, (void *)&un); - - if (rc == SQLITE_OK) { - pthread_mutex_lock(&un.mutex); - if (!un.fired) - pthread_cond_wait (&un.cond, &un.mutex); - pthread_mutex_unlock(&un.mutex); - } - - pthread_cond_destroy (&un.cond); - pthread_mutex_destroy (&un.mutex); - - return rc; -} - -static int -sqlite3_blocking_step(sqlite3_stmt *stmt) -{ - int rc; - while (SQLITE_LOCKED == (rc = sqlite3_step(stmt))) { - rc = wait_for_unlock_notify(sqlite3_db_handle(stmt)); - if (rc != SQLITE_OK) - break; - sqlite3_reset(stmt); - } - return rc; -} - -static int -sqlite3_blocking_prepare_v2(sqlite3 *db, const char *sql, int sql_len, sqlite3_stmt **pstmt, const char **pz) -{ - int rc; - while (SQLITE_LOCKED == (rc = sqlite3_prepare_v2(db, sql, sql_len, pstmt, pz))) { - rc = wait_for_unlock_notify(db); - if (rc != SQLITE_OK) - break; - } - return rc; -} - -static int -sqlite3_blocking_exec(sqlite3 *db, const char *sql, int (*callback)(void *, int, char **, char **), void *arg, char **errmsg) -{ - int rc; - while (SQLITE_LOCKED == (rc = sqlite3_exec(db, sql, callback, arg, errmsg))) { - rc = wait_for_unlock_notify(db); - if (rc != SQLITE_OK) - break; - } - return rc; -} - -#if 0 - -#define SQLITE_QUERY_TIMEOUT 3 - -#define EXEC_SQLITE(status, action) \ - do {\ - long t = (SQLITE_QUERY_TIMEOUT * G_USEC_PER_SEC);\ - int x = 0;\ - do {\ - status = (action);\ - if (((status == SQLITE_BUSY) || (status == SQLITE_LOCKED)) && (x++ <= 9))\ - g_usleep(t/(rand() % 3 + 10));\ - else\ - break;\ - } while (1);\ - } while (0) - -#endif /* 0 */ - -typedef struct SQLiteDBConnPool { - DBConnPool parent; - char *db_path; -} SQLiteDBConnPool; - -DBConnPool * -sqlite_db_conn_pool_new (const char *db_path) -{ - SQLiteDBConnPool *pool = g_new0 (SQLiteDBConnPool, 1); - pool->db_path = g_strdup(db_path); - - return (DBConnPool *)pool; -} - -void -sqlite_db_conn_pool_free (DBConnPool *vpool) -{ - if (!vpool) - return; - - SQLiteDBConnPool *pool = (SQLiteDBConnPool *)vpool; - - g_free (pool->db_path); - g_free (pool); -} - -typedef struct SQLiteDBConnection { - DBConnection parent; - sqlite3 *db; -} SQLiteDBConnection; - -DBConnection * -sqlite_get_db_connection (DBConnPool *vpool, GError **error) -{ - SQLiteDBConnPool *pool = (SQLiteDBConnPool *)vpool; - sqlite3 *db; - int result; - const char *errmsg; - SQLiteDBConnection *conn; - - result = sqlite3_open_v2 (pool->db_path, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_SHAREDCACHE, NULL); - if (result != SQLITE_OK) { - errmsg = sqlite3_errmsg(db); - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Failed to open sqlite db: %s", - errmsg ? errmsg : "no error given"); - return NULL; - } - - conn = g_new0 (SQLiteDBConnection, 1); - conn->db = db; - - return (DBConnection *)conn; -} - -void -sqlite_db_connection_close (DBConnection *vconn) -{ - if (!vconn) - return; - - SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; - - sqlite3_close (conn->db); - - g_free (conn); -} - -gboolean -sqlite_db_connection_ping (DBConnection *vconn) -{ - return TRUE; -} - -gboolean -sqlite_db_connection_execute (DBConnection *vconn, const char *sql, GError **error) -{ - SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; - char *errmsg = NULL; - int rc; - - rc = sqlite3_blocking_exec (conn->db, sql, NULL, NULL, &errmsg); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_exec failed: %s", - errmsg ? errmsg : "no error given"); - if (errmsg) - sqlite3_free (errmsg); - return FALSE; - } - - return TRUE; -} - -typedef struct SQLiteResultSet { - ResultSet parent; - sqlite3 *db; - sqlite3_stmt *stmt; - int column_count; -} SQLiteResultSet; - -void -sqlite_result_set_free (ResultSet *vr) -{ - if (!vr) - return; - - SQLiteResultSet *r = (SQLiteResultSet *)vr; - - sqlite3_finalize (r->stmt); - - g_free (r); -} - -ResultSet * -sqlite_execute_query (DBConnection *vconn, const char *sql, GError **error) -{ - SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; - sqlite3_stmt *stmt; - int rc; - SQLiteResultSet *r; - - rc = sqlite3_blocking_prepare_v2 (conn->db, sql, -1, &stmt, NULL); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_prepare_v2 failed: %s", sqlite3_errmsg(conn->db)); - return NULL; - } - - r = g_new0 (SQLiteResultSet, 1); - r->db = conn->db; - r->stmt = stmt; - r->column_count = sqlite3_column_count (stmt); - - return (ResultSet *)r; -} - -gboolean -sqlite_result_set_next (ResultSet *vr, GError **error) -{ - SQLiteResultSet *r = (SQLiteResultSet *)vr; - int rc; - - rc = sqlite3_blocking_step (r->stmt); - if (rc != SQLITE_ROW && rc != SQLITE_DONE) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_step failed: %s", sqlite3_errmsg(r->db)); - return FALSE; - } - - return (rc == SQLITE_ROW); -} - -const char * -sqlite_result_set_get_string (ResultSet *vr, int i, GError **error) -{ - SQLiteResultSet *r = (SQLiteResultSet *)vr; - - if (i < 0 || i >= r->column_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return NULL; - } - - return (const char *)sqlite3_column_text (r->stmt, i); -} - -int -sqlite_result_set_get_column_count (ResultSet *vr) -{ - return ((SQLiteResultSet *)vr)->column_count; -} - -typedef struct SQLiteDBStmt { - DBStmt parent; - int param_count; - sqlite3 *db; - sqlite3_stmt *stmt; -} SQLiteDBStmt; - -DBStmt * -sqlite_prepare_statement (DBConnection *vconn, const char *sql, GError **error) -{ - SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; - sqlite3_stmt *stmt; - int rc; - SQLiteDBStmt *ret; - - rc = sqlite3_blocking_prepare_v2 (conn->db, sql, -1, &stmt, NULL); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_prepare_v2 failed: %s", sqlite3_errmsg(conn->db)); - return NULL; - } - - ret = g_new0 (SQLiteDBStmt, 1); - ret->stmt = stmt; - ret->db = conn->db; - ret->param_count = sqlite3_bind_parameter_count (stmt); - - return (DBStmt *)ret; -} - -gboolean -sqlite_stmt_set_int (DBStmt *vstmt, int i, int x, GError **error) -{ - SQLiteDBStmt *stmt = (SQLiteDBStmt *)vstmt; - int rc; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - rc = sqlite3_bind_int (stmt->stmt, i+1, x); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_bind_int failed: %s", sqlite3_errmsg(stmt->db)); - return FALSE; - } - - return TRUE; -} - -gboolean -sqlite_stmt_set_int64 (DBStmt *vstmt, int i, gint64 x, GError **error) -{ - SQLiteDBStmt *stmt = (SQLiteDBStmt *)vstmt; - int rc; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - rc = sqlite3_bind_int64 (stmt->stmt, i+1, x); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_bind_int failed: %s", sqlite3_errmsg(stmt->db)); - return FALSE; - } - - return TRUE; -} - -gboolean -sqlite_stmt_set_string (DBStmt *vstmt, int i, const char *s, GError **error) -{ - SQLiteDBStmt *stmt = (SQLiteDBStmt *)vstmt; - int rc; - - if (i < 0 || i >= stmt->param_count) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Column index is out of range."); - return FALSE; - } - - rc = sqlite3_bind_text (stmt->stmt, i+1, s, -1, SQLITE_TRANSIENT); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_bind_int failed: %s", sqlite3_errmsg(stmt->db)); - return FALSE; - } - - return TRUE; -} - -gboolean -sqlite_db_stmt_execute (DBStmt *vstmt, GError **error) -{ - SQLiteDBStmt *stmt = (SQLiteDBStmt *)vstmt; - int rc; - - rc = sqlite3_blocking_step (stmt->stmt); - if (rc == SQLITE_DONE) { - sqlite3_reset (stmt->stmt); - return TRUE; - } else if (rc == SQLITE_ROW) { - sqlite3_reset (stmt->stmt); - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "Select statement not allowed in db_stmt_execute."); - return FALSE; - } else { - sqlite3_reset (stmt->stmt); - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "sqlite3_step failed: %s", sqlite3_errmsg(stmt->db)); - return FALSE; - } -} - -ResultSet * -sqlite_db_stmt_execute_query (DBStmt *vstmt, GError **error) -{ - SQLiteDBStmt *stmt = (SQLiteDBStmt *)vstmt; - SQLiteResultSet *r; - - r = g_new0 (SQLiteResultSet, 1); - r->db = stmt->db; - r->stmt = stmt->stmt; - r->column_count = sqlite3_column_count (r->stmt); - - return (ResultSet *)r; -} - -void -sqlite_db_stmt_free (DBStmt *vstmt) -{ - if (!vstmt) - return; - - SQLiteDBStmt *stmt = (SQLiteDBStmt *)vstmt; - - if (!stmt->parent.result_set) { - sqlite3_finalize (stmt->stmt); - } - - g_free (stmt); -} - -gboolean -sqlite_db_begin_transaction (DBConnection *vconn, GError **error) -{ - SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; - int rc; - - rc = sqlite3_blocking_exec (conn->db, "BEGIN TRANSACTION;", NULL, NULL, NULL); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "begin transaction failed: %s", sqlite3_errmsg(conn->db)); - return FALSE; - } - - return TRUE; -} - -gboolean -sqlite_db_commit (DBConnection *vconn, GError **error) -{ - SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; - int rc; - - rc = sqlite3_blocking_exec (conn->db, "COMMIT TRANSACTION;", NULL, NULL, NULL); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "commit transaction failed: %s", sqlite3_errmsg(conn->db)); - return FALSE; - } - - return TRUE; -} - -gboolean -sqlite_db_rollback (DBConnection *vconn, GError **error) -{ - SQLiteDBConnection *conn = (SQLiteDBConnection *)vconn; - int rc; - - rc = sqlite3_blocking_exec (conn->db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL); - if (rc != SQLITE_OK) { - g_set_error (error, SEAF_DB_ERROR_DOMAIN, SEAF_DB_ERROR_CODE, - "rollback transaction failed: %s", sqlite3_errmsg(conn->db)); - return FALSE; - } - - return TRUE; -} diff --git a/net/common/db-wrapper/sqlite-db-ops.h b/net/common/db-wrapper/sqlite-db-ops.h deleted file mode 100644 index 9fb1bd8..0000000 --- a/net/common/db-wrapper/sqlite-db-ops.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef SQLITE_DB_OPS_H -#define SQLITE_DB_OPS_H - -DBConnPool * -sqlite_db_conn_pool_new (const char *db_path); - -void -sqlite_db_conn_pool_free (DBConnPool *vpool); - -DBConnection * -sqlite_get_db_connection (DBConnPool *vpool, GError **error); - -void -sqlite_db_connection_close (DBConnection *vconn); - -gboolean -sqlite_db_connection_ping (DBConnection *vconn); - -gboolean -sqlite_db_connection_execute (DBConnection *vconn, const char *sql, GError **error); - -void -sqlite_result_set_free (ResultSet *vr); - -ResultSet * -sqlite_execute_query (DBConnection *vconn, const char *sql, GError **error); - -gboolean -sqlite_result_set_next (ResultSet *vr, GError **error); - -const char * -sqlite_result_set_get_string (ResultSet *vr, int i, GError **error); - -int -sqlite_result_set_get_column_count (ResultSet *vr); - -DBStmt * -sqlite_prepare_statement (DBConnection *vconn, const char *sql, GError **error); - -gboolean -sqlite_stmt_set_int (DBStmt *vstmt, int i, int x, GError **error); - -gboolean -sqlite_stmt_set_int64 (DBStmt *vstmt, int i, gint64 x, GError **error); - -gboolean -sqlite_stmt_set_string (DBStmt *vstmt, int i, const char *s, GError **error); - -gboolean -sqlite_db_stmt_execute (DBStmt *vstmt, GError **error); - -ResultSet * -sqlite_db_stmt_execute_query (DBStmt *vstmt, GError **error); - -void -sqlite_db_stmt_free (DBStmt *vstmt); - -gboolean -sqlite_db_begin_transaction (DBConnection *vconn, GError **error); - -gboolean -sqlite_db_commit (DBConnection *vconn, GError **error); - -gboolean -sqlite_db_rollback (DBConnection *vconn, GError **error); - -#endif diff --git a/net/server/Makefile.am b/net/server/Makefile.am index 7cda288..0056078 100644 --- a/net/server/Makefile.am +++ b/net/server/Makefile.am @@ -7,6 +7,7 @@ AM_CPPFLAGS = @GLIB2_CFLAGS@ @GOBJECT_CFLAGS@ \ -I$(top_builddir)/include \ -I$(top_builddir)/lib \ @SEARPC_CFLAGS@ \ + @MYSQL_CFLAGS@ \ -Wall bin_PROGRAMS = ccnet-server @@ -46,11 +47,10 @@ ccnet_server_SOURCES = ccnet-server.c \ $(common_srcs) ccnet_server_LDADD = @LIBEVENT_LIBS@ $(top_builddir)/lib/libccnetd.la \ - $(top_builddir)/net/common/db-wrapper/libdbwrapper.la \ @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 \ -lpthread \ @LIB_WS32@ @LIB_INTL@ @LIB_IPHLPAPI@ @SEARPC_LIBS@ \ - @LDAP_LIBS@ @MYSQL_LIBS@ @PGSQL_LIBS@ + @LDAP_LIBS@ @MYSQL_LIBS@ -lsqlite3 ccnet_server_LDFLAGS = @CONSOLE@ -no-undefined diff --git a/net/server/group-mgr.c b/net/server/group-mgr.c index 055e12d..d0d162f 100644 --- a/net/server/group-mgr.c +++ b/net/server/group-mgr.c @@ -197,11 +197,11 @@ static int check_db_table (CcnetGroupManager *manager, CcnetDB *db) if (ccnet_db_query (db, sql) < 0) return -1; - if (!pgsql_index_exists (db, "groupuser_username_idx")) { - sql = "CREATE INDEX groupuser_username_idx ON GroupUser (user_name)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "groupuser_username_idx")) { + // sql = "CREATE INDEX groupuser_username_idx ON GroupUser (user_name)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} sql = "CREATE TABLE IF NOT EXISTS GroupDNPair (group_id INTEGER," " dn VARCHAR(255))"; @@ -213,11 +213,11 @@ static int check_db_table (CcnetGroupManager *manager, CcnetDB *db) if (ccnet_db_query (db, sql) < 0) return -1; - if (!pgsql_index_exists (db, "structure_path_idx")) { - sql = "CREATE INDEX structure_path_idx ON GroupStructure (path)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "structure_path_idx")) { + // sql = "CREATE INDEX structure_path_idx ON GroupStructure (path)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} } g_string_free (group_sql, TRUE); @@ -410,14 +410,20 @@ int ccnet_group_manager_create_org_group (CcnetGroupManager *mgr, static gboolean check_group_staff (CcnetDB *db, int group_id, const char *user_name, gboolean in_structure) { + gboolean exists, err; if (!in_structure) { - return ccnet_db_statement_exists (db, "SELECT group_id FROM GroupUser WHERE " - "group_id = ? AND user_name = ? AND " - "is_staff = 1", - 2, "int", group_id, "string", user_name); + exists = ccnet_db_statement_exists (db, "SELECT group_id FROM GroupUser WHERE " + "group_id = ? AND user_name = ? AND " + "is_staff = 1", &err, + 2, "int", group_id, "string", user_name); + if (err) { + ccnet_warning ("DB error when check staff user exist in GroupUser.\n"); + return FALSE; + } + return exists; } - gboolean exists; + GString *sql = g_string_new(""); g_string_printf (sql, "SELECT path FROM GroupStructure WHERE group_id=?"); char *path = ccnet_db_statement_get_string (db, sql->str, 1, "int", group_id); @@ -426,18 +432,23 @@ check_group_staff (CcnetDB *db, int group_id, const char *user_name, gboolean in if (!path) { exists = ccnet_db_statement_exists (db, "SELECT group_id FROM GroupUser WHERE " "group_id = ? AND user_name = ? AND " - "is_staff = 1", + "is_staff = 1", &err, 2, "int", group_id, "string", user_name); } else { g_string_printf (sql, "SELECT group_id FROM GroupUser WHERE " "group_id IN (%s) AND user_name = ? AND " "is_staff = 1", path); - exists = ccnet_db_statement_exists (db, sql->str, + exists = ccnet_db_statement_exists (db, sql->str, &err, 1, "string", user_name); } g_string_free (sql, TRUE); g_free (path); + if (err) { + ccnet_warning ("DB error when check staff user exist in GroupUser.\n"); + return FALSE; + } + return exists; } @@ -448,7 +459,7 @@ int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, { CcnetDB *db = mgr->priv->db; GString *sql = g_string_new (""); - gboolean exists; + gboolean exists, err; const char *table_name = mgr->priv->table_name; /* No permission check here, since both group staff and seahub staff @@ -459,7 +470,12 @@ int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, g_string_printf (sql, "SELECT 1 FROM \"%s\" WHERE parent_group_id=?", table_name); else g_string_printf (sql, "SELECT 1 FROM `%s` WHERE parent_group_id=?", table_name); - exists = ccnet_db_statement_exists (db, sql->str, 1, "int", group_id); + exists = ccnet_db_statement_exists (db, sql->str, &err, 1, "int", group_id); + if (err) { + ccnet_warning ("DB error when check remove group.\n"); + g_string_free (sql, TRUE); + return -1; + } if (exists) { ccnet_warning ("Failed to remove group [%d] whose child group must be removed first.\n", group_id); g_string_free (sql, TRUE); @@ -489,17 +505,21 @@ check_group_exists (CcnetGroupManager *mgr, CcnetDB *db, int group_id) { GString *sql = g_string_new (""); const char *table_name = mgr->priv->table_name; - gboolean exists; + gboolean exists, err; if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) { g_string_printf (sql, "SELECT group_id FROM \"%s\" WHERE group_id=?", table_name); - exists = ccnet_db_statement_exists (db, sql->str, 1, "int", group_id); + exists = ccnet_db_statement_exists (db, sql->str, &err, 1, "int", group_id); } else { g_string_printf (sql, "SELECT group_id FROM `%s` WHERE group_id=?", table_name); - exists = ccnet_db_statement_exists (db, sql->str, 1, "int", group_id); + exists = ccnet_db_statement_exists (db, sql->str, &err, 1, "int", group_id); } g_string_free (sql, TRUE); + if (err) { + ccnet_warning ("DB error when check group exist.\n"); + return FALSE; + } return exists; } @@ -1088,9 +1108,14 @@ ccnet_group_manager_is_group_user (CcnetGroupManager *mgr, { CcnetDB *db = mgr->priv->db; - gboolean exists = ccnet_db_statement_exists (db, "SELECT group_id FROM GroupUser " - "WHERE group_id=? AND user_name=?", - 2, "int", group_id, "string", user); + gboolean exists, err; + exists = ccnet_db_statement_exists (db, "SELECT group_id FROM GroupUser " + "WHERE group_id=? AND user_name=?", &err, + 2, "int", group_id, "string", user); + if (err) { + ccnet_warning ("DB error when check user exist in GroupUser.\n"); + return 0; + } if (!in_structure || exists) return exists ? 1 : 0; diff --git a/net/server/org-mgr.c b/net/server/org-mgr.c index ead5413..5b9b6ce 100644 --- a/net/server/org-mgr.c +++ b/net/server/org-mgr.c @@ -175,11 +175,11 @@ static int check_db_table (CcnetDB *db) if (ccnet_db_query (db, sql) < 0) return -1; - if (!pgsql_index_exists (db, "orguser_email_idx")) { - sql = "CREATE INDEX orguser_email_idx ON OrgUser (email)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "orguser_email_idx")) { + // sql = "CREATE INDEX orguser_email_idx ON OrgUser (email)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} sql = "CREATE TABLE IF NOT EXISTS OrgGroup (org_id INTEGER, " "group_id INTEGER, " @@ -187,11 +187,11 @@ static int check_db_table (CcnetDB *db) if (ccnet_db_query (db, sql) < 0) return -1; - if (!pgsql_index_exists (db, "orggroup_groupid_idx")) { - sql = "CREATE INDEX orggroup_groupid_idx ON OrgGroup (group_id)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "orggroup_groupid_idx")) { + // sql = "CREATE INDEX orggroup_groupid_idx ON OrgGroup (group_id)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} } return 0; @@ -548,10 +548,17 @@ ccnet_org_manager_is_org_group (CcnetOrgManager *mgr, int group_id, GError **error) { + gboolean exists, err; + CcnetDB *db = mgr->priv->db; - return ccnet_db_statement_exists (db, "SELECT group_id FROM OrgGroup " - "WHERE group_id = ?", 1, "int", group_id); + exists = ccnet_db_statement_exists (db, "SELECT group_id FROM OrgGroup " + "WHERE group_id = ?", &err, 1, "int", group_id); + if (err) { + ccnet_warning ("DB error when check group exist in OrgGroup.\n"); + return 0; + } + return exists; } int @@ -724,11 +731,18 @@ ccnet_org_manager_org_user_exists (CcnetOrgManager *mgr, const char *email, GError **error) { + gboolean exists, err; + CcnetDB *db = mgr->priv->db; - return ccnet_db_statement_exists (db, "SELECT org_id FROM OrgUser WHERE " - "org_id = ? AND email = ?", - 2, "int", org_id, "string", email); + exists = ccnet_db_statement_exists (db, "SELECT org_id FROM OrgUser WHERE " + "org_id = ? AND email = ?", &err, + 2, "int", org_id, "string", email); + if (err) { + ccnet_warning ("DB error when check user exist in OrgUser.\n"); + return 0; + } + return exists; } char * diff --git a/net/server/server-session.c b/net/server/server-session.c index 7d415dc..a324669 100644 --- a/net/server/server-session.c +++ b/net/server/server-session.c @@ -195,7 +195,7 @@ static int init_mysql_database (CcnetSession *session) #endif -#ifdef HAVE_POSTGRESQL +#if 0 static int init_pgsql_database (CcnetSession *session) { @@ -263,7 +263,7 @@ load_database_config (CcnetSession *session) ret = init_mysql_database (session); } #endif -#ifdef HAVE_POSTGRESQL +#if 0 else if (strncasecmp (engine, DB_PGSQL, sizeof(DB_PGSQL)) == 0) { ccnet_debug ("Use database PostgreSQL\n"); ret = init_pgsql_database (session); diff --git a/net/server/user-mgr.c b/net/server/user-mgr.c index 17e2f89..d4c074f 100644 --- a/net/server/user-mgr.c +++ b/net/server/user-mgr.c @@ -666,11 +666,11 @@ static int check_db_table (CcnetDB *db) if (ccnet_db_query (db, sql) < 0) return -1; - if (!pgsql_index_exists (db, "emailuser_reference_id_idx")) { - sql = "CREATE UNIQUE INDEX emailuser_reference_id_idx ON EmailUser (reference_id)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "emailuser_reference_id_idx")) { + // sql = "CREATE UNIQUE INDEX emailuser_reference_id_idx ON EmailUser (reference_id)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} sql = "CREATE TABLE IF NOT EXISTS Binding (email VARCHAR(255), peer_id CHAR(41)," "UNIQUE (peer_id))"; @@ -682,11 +682,11 @@ static int check_db_table (CcnetDB *db) if (ccnet_db_query (db, sql) < 0) return -1; - if (!pgsql_index_exists (db, "userrole_email_idx")) { - sql = "CREATE INDEX userrole_email_idx ON UserRole (email)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "userrole_email_idx")) { + // sql = "CREATE INDEX userrole_email_idx ON UserRole (email)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} sql = "CREATE TABLE IF NOT EXISTS LDAPUsers (" "id SERIAL PRIMARY KEY, " @@ -696,17 +696,17 @@ static int check_db_table (CcnetDB *db) if (ccnet_db_query (db, sql) < 0) return -1; - if (!pgsql_index_exists (db, "ldapusers_email_idx")) { - sql = "CREATE UNIQUE INDEX ldapusers_email_idx ON LDAPUsers (email)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "ldapusers_email_idx")) { + // sql = "CREATE UNIQUE INDEX ldapusers_email_idx ON LDAPUsers (email)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} - if (!pgsql_index_exists (db, "ldapusers_reference_id_idx")) { - sql = "CREATE UNIQUE INDEX ldapusers_reference_id_idx ON LDAPUsers (reference_id)"; - if (ccnet_db_query (db, sql) < 0) - return -1; - } + //if (!pgsql_index_exists (db, "ldapusers_reference_id_idx")) { + // sql = "CREATE UNIQUE INDEX ldapusers_reference_id_idx ON LDAPUsers (reference_id)"; + // if (ccnet_db_query (db, sql) < 0) + // return -1; + //} sql = "CREATE TABLE IF NOT EXISTS LDAPConfig (cfg_group VARCHAR(255) NOT NULL," "cfg_key VARCHAR(255) NOT NULL, value VARCHAR(255), property INTEGER)"; @@ -1789,20 +1789,22 @@ ccnet_user_manager_set_reference_id (CcnetUserManager *manager, { int rc; char *sql; - gboolean exists; + gboolean exists, err; #ifdef HAVE_LDAP if (manager->use_ldap) { sql = "SELECT email FROM LDAPUsers WHERE email = ?"; - exists = ccnet_db_statement_exists (manager->priv->db, sql, + exists = ccnet_db_statement_exists (manager->priv->db, sql, &err, 1, "string", primary_id); + if (err) + return -1; /* Make sure reference_id is unique */ if (exists) { sql = "SELECT 1 FROM EmailUser e, LDAPUsers l " "WHERE (e.reference_id=? AND e.email!=?) OR " "(l.reference_id=? AND l.email!=?) OR " "(e.email=? AND e.email!=?) OR (l.email=? AND l.email!=?)"; - exists = ccnet_db_statement_exists (manager->priv->db, sql, + exists = ccnet_db_statement_exists (manager->priv->db, sql, &err, 8, "string", reference_id, "string", primary_id, "string", reference_id, @@ -1811,6 +1813,8 @@ ccnet_user_manager_set_reference_id (CcnetUserManager *manager, "string", primary_id, "string", reference_id, "string", primary_id); + if (err) + return -1; if (exists) { ccnet_warning ("Failed to set reference id, email '%s' exists\n", reference_id); return -1; @@ -1828,15 +1832,17 @@ ccnet_user_manager_set_reference_id (CcnetUserManager *manager, #endif sql = "SELECT email FROM EmailUser WHERE email = ?"; - exists = ccnet_db_statement_exists (manager->priv->db, sql, + exists = ccnet_db_statement_exists (manager->priv->db, sql, &err, 1, "string", primary_id); + if (err) + return -1; /* Make sure reference_id is unique */ if (exists) { sql = "SELECT 1 FROM EmailUser e, LDAPUsers l " "WHERE (e.reference_id=? AND e.email!=?) OR " "(l.reference_id=? AND l.email!=?) OR " "(e.email=? AND e.email!=?) OR (l.email=? AND l.email!=?)"; - exists = ccnet_db_statement_exists (manager->priv->db, sql, + exists = ccnet_db_statement_exists (manager->priv->db, sql, &err, 8, "string", reference_id, "string", primary_id, "string", reference_id, @@ -1845,6 +1851,8 @@ ccnet_user_manager_set_reference_id (CcnetUserManager *manager, "string", primary_id, "string", reference_id, "string", primary_id); + if (err) + return -1; if (exists) { ccnet_warning ("Failed to set reference id, email '%s' exists\n", reference_id); return -1;