From fd75ea8a3fd6c1506abb0a9dc38bd6dd11c7c6b7 Mon Sep 17 00:00:00 2001 From: Giovanni Mele Date: Mon, 9 May 2016 19:22:16 +0200 Subject: [PATCH] db_unixodbc: some ODBC drivers do not support ODBC replace query --- modules/db_unixodbc/connection.h | 2 + modules/db_unixodbc/db_unixodbc.c | 7 ++- modules/db_unixodbc/dbase.c | 50 ++++++++++++++++++- modules/db_unixodbc/dbase.h | 7 +++ modules/db_unixodbc/doc/db_unixodbc_admin.xml | 30 +++++++++++ 5 files changed, 94 insertions(+), 2 deletions(-) diff --git a/modules/db_unixodbc/connection.h b/modules/db_unixodbc/connection.h index 2920968b578..ecd7416c1fb 100644 --- a/modules/db_unixodbc/connection.h +++ b/modules/db_unixodbc/connection.h @@ -63,6 +63,7 @@ struct my_con SQLHDBC dbc; /*!< Connection representation */ char** row; /*!< Actual row in the result */ time_t timestamp; /*!< Timestamp of last query */ + int statement_res; /*!< ODBC real statement result */ }; /* @@ -74,6 +75,7 @@ struct my_con #define CON_TIMESTAMP(db_con) (((struct my_con*)((db_con)->tail))->timestamp) #define CON_ID(db_con) (((struct my_con*)((db_con)->tail))->id) #define CON_ENV(db_con) (((struct my_con*)((db_con)->tail))->env) +#define CON_QUERY_RESULT(db_con) (((struct my_con*)((db_con)->tail))->statement_res) #define MAX_CONN_STR_LEN 2048 diff --git a/modules/db_unixodbc/db_unixodbc.c b/modules/db_unixodbc/db_unixodbc.c index 08ea8279443..020ea5e9e04 100644 --- a/modules/db_unixodbc/db_unixodbc.c +++ b/modules/db_unixodbc/db_unixodbc.c @@ -37,6 +37,7 @@ int ping_interval = 5 * 60; /* Default is 5 minutes */ int auto_reconnect = 1; /* Default is enabled */ int use_escape_common = 0; /* Enable common escaping */ +int replace_query = 1; /* Enable ODBC replace query */ MODULE_VERSION @@ -59,6 +60,7 @@ static param_export_t params[] = { {"ping_interval", INT_PARAM, &ping_interval}, {"auto_reconnect", INT_PARAM, &auto_reconnect}, {"use_escape_common", INT_PARAM, &use_escape_common}, + {"replace_query", INT_PARAM, &replace_query}, {0, 0, 0} }; @@ -95,7 +97,10 @@ int db_unixodbc_bind_api(db_func_t *dbb) dbb->insert = db_unixodbc_insert; dbb->delete = db_unixodbc_delete; dbb->update = db_unixodbc_update; - dbb->replace = db_unixodbc_replace; + if (replace_query) + dbb->replace = db_unixodbc_replace; + else + dbb->replace = db_unixodbc_update_or_insert; return 0; } diff --git a/modules/db_unixodbc/dbase.c b/modules/db_unixodbc/dbase.c index 346010c44d4..bef60e24cea 100644 --- a/modules/db_unixodbc/dbase.c +++ b/modules/db_unixodbc/dbase.c @@ -160,7 +160,8 @@ static int db_unixodbc_submit_query(const db1_con_t* _h, const str* _s) SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h)); } } - + /* Store the ODBC query result */ + CON_QUERY_RESULT(_h) = ret; return ret; } @@ -485,6 +486,53 @@ int db_unixodbc_replace(const db1_con_t* _h, const db_key_t* _k, const db_val_t* db_unixodbc_submit_query); } + +/* + * Just like insert, but update the row if it exists otherwise insert it. + * For DB not supporting the replace query. + */ +int db_unixodbc_update_or_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, + const int _n, const int _un, const int _m) +{ + if(_un > _n) + { + LM_ERR("number of columns for unique key is too high\n"); + return -1; + } + + if(_un > 0) + { + /* Query error */ + if(db_unixodbc_update(_h, _k, 0, _v, _k + _un, + _v + _un, _un, _n -_un)< 0) + { + LM_ERR("update failed\n"); + return -1; + } + /* No row updated ? */ + else if (CON_QUERY_RESULT(_h) == SQL_NO_DATA_FOUND) + { + /* Do an insert then */ + if(db_unixodbc_insert(_h, _k, _v, _n)< 0) + { + LM_ERR("insert failed\n"); + return -1; + } + LM_DBG("inserted new record in database table\n"); + } else { + LM_DBG("updated record in database table\n"); + } + } else { + if(db_unixodbc_insert(_h, _k, _v, _n)< 0) + { + LM_ERR("direct insert failed\n"); + return -1; + } + LM_DBG("directly inserted new record in database table\n"); + } + return 0; +} + /* * Store name of table that will be used by * subsequent database functions diff --git a/modules/db_unixodbc/dbase.h b/modules/db_unixodbc/dbase.h index 7cf1f3676ac..0355c07a9a3 100644 --- a/modules/db_unixodbc/dbase.h +++ b/modules/db_unixodbc/dbase.h @@ -92,6 +92,13 @@ const db_key_t* _uk, const db_val_t* _uv, const int _n, const int _un); int db_unixodbc_replace(const db1_con_t* handle, const db_key_t* keys, const db_val_t* vals, const int n, const int _un, const int _m); +/* + * Just like insert, but update the row if it exists or insert it if not. This function is used when + * the odbc replace query is not supported. + */ +int db_unixodbc_update_or_insert(const db1_con_t* handle, const db_key_t* keys, const db_val_t* vals, + const int n, const int _un, const int _m); + /* * Store name of table that will be used by * subsequent database functions diff --git a/modules/db_unixodbc/doc/db_unixodbc_admin.xml b/modules/db_unixodbc/doc/db_unixodbc_admin.xml index 8b1c7f40d38..85d36d9dd16 100644 --- a/modules/db_unixodbc/doc/db_unixodbc_admin.xml +++ b/modules/db_unixodbc/doc/db_unixodbc_admin.xml @@ -131,6 +131,25 @@ modparam("db_unixodbc", "use_escape_common", 1) +
+ <varname>replace_query</varname> (int) + + Tells if the ODBC replace query is supported by the DB odbc driver. + + + + Default value is 1 seconds. + + + + Set the <quote>replace_query</quote> parameter + +... +modparam("db_unixodbc", "replace_query", 0) +... + + +
@@ -199,6 +218,17 @@ shell>safe_mysqld --user=mysql --socket=/var/lib/mysql/mysql.sock The connector search the socket in /var/lib/mysql/mysql.sock and not in /tmp/mysql.sock + + + REMARK: Oracle ODBC driver doesn't support ODBC query. To disable its usage + and replace the replace query by an update or insert query, use the parameter: + + +.... +modparam("db_unixodbc", "replace_query", 0) +.... + +