Merged revisions 73316 via svnmerge from
[asterisk/asterisk.git] / res / res_config_odbc.c
index 81df461..7715166 100644 (file)
@@ -30,6 +30,8 @@
 
 /*** MODULEINFO
        <depend>unixodbc</depend>
+       <depend>ltdl</depend>
+       <depend>res_odbc</depend>
  ***/
 
 #include "asterisk.h"
@@ -52,8 +54,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/res_odbc.h"
 #include "asterisk/utils.h"
 
-LOCAL_USER_DECL;
-
 static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
 {
        struct odbc_obj *obj;
@@ -74,7 +74,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
        SQLSMALLINT datatype;
        SQLSMALLINT decimaldigits;
        SQLSMALLINT nullable;
-       SQLINTEGER indicator;
+       SQLLEN indicator;
        va_list aq;
        
        va_copy(aq, ap);
@@ -83,21 +83,21 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
        if (!table)
                return NULL;
 
-       obj = odbc_request_obj(database, 0);
+       obj = ast_odbc_request_obj(database, 0);
        if (!obj)
                return NULL;
 
        res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
        newparam = va_arg(aq, const char *);
        if (!newparam)  {
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
        newval = va_arg(aq, const char *);
@@ -113,7 +113,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
        
@@ -125,12 +125,12 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
        }
        
-       res = odbc_smart_execute(obj, stmt);
+       res = ast_odbc_smart_execute(obj, stmt);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
@@ -138,20 +138,20 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
        res = SQLFetch(stmt);
        if (res == SQL_NO_DATA) {
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                 return NULL;
        }
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
        for (x = 0; x < colcount; x++) {
@@ -163,40 +163,42 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                        ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
                        if (var)
                                ast_variables_destroy(var);
-                       odbc_release_obj(obj);
+                       ast_odbc_release_obj(obj);
                        return NULL;
                }
 
                indicator = 0;
                res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
                if (indicator == SQL_NULL_DATA)
-                       continue;
+                       rowdata[0] = '\0';
+               else if (ast_strlen_zero(rowdata)) {
+                       /* Because we encode the empty string for a NULL, we will encode
+                        * actual empty strings as a string containing a single whitespace. */
+                       ast_copy_string(rowdata, " ", sizeof(rowdata));
+               }
 
                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                        ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
                        if (var)
                                ast_variables_destroy(var);
-                       odbc_release_obj(obj);
+                       ast_odbc_release_obj(obj);
                        return NULL;
                }
                stringp = rowdata;
                while(stringp) {
                        chunk = strsep(&stringp, ";");
-                       if (!ast_strlen_zero(ast_strip(chunk))) {
-                               if (prev) {
-                                       prev->next = ast_variable_new(coltitle, chunk);
-                                       if (prev->next)
-                                               prev = prev->next;
-                                       } else 
-                                               prev = var = ast_variable_new(coltitle, chunk);
-                                       
-                       }
+                       if (prev) {
+                               prev->next = ast_variable_new(coltitle, chunk);
+                               if (prev->next)
+                                       prev = prev->next;
+                       } else 
+                               prev = var = ast_variable_new(coltitle, chunk);
                }
        }
 
 
        SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-       odbc_release_obj(obj);
+       ast_odbc_release_obj(obj);
        return var;
 }
 
@@ -218,37 +220,34 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        struct ast_variable *var=NULL;
        struct ast_config *cfg=NULL;
        struct ast_category *cat=NULL;
-       struct ast_realloca ra;
        SQLULEN colsize;
        SQLSMALLINT colcount=0;
        SQLSMALLINT datatype;
        SQLSMALLINT decimaldigits;
        SQLSMALLINT nullable;
-       SQLINTEGER indicator;
+       SQLLEN indicator;
 
        va_list aq;
        va_copy(aq, ap);
-       
-       
+
        if (!table)
                return NULL;
-       memset(&ra, 0, sizeof(ra));
 
-       obj = odbc_request_obj(database, 0);
+       obj = ast_odbc_request_obj(database, 0);
        if (!obj)
                return NULL;
 
        res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
        newparam = va_arg(aq, const char *);
        if (!newparam)  {
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
        initfield = ast_strdupa(newparam);
@@ -269,7 +268,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
        
@@ -281,12 +280,12 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
                SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
        }
                
-       res = odbc_smart_execute(obj, stmt);
+       res = ast_odbc_smart_execute(obj, stmt);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
@@ -294,7 +293,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
@@ -302,7 +301,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        if (!cfg) {
                ast_log(LOG_WARNING, "Out of memory!\n");
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
@@ -353,7 +352,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        }
 
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-       odbc_release_obj(obj);
+       ast_odbc_release_obj(obj);
        return cfg;
 }
 
@@ -373,21 +372,21 @@ static int update_odbc(const char *database, const char *table, const char *keyf
        if (!table)
                return -1;
 
-       obj = odbc_request_obj(database, 0);
+       obj = ast_odbc_request_obj(database, 0);
        if (!obj)
                return -1;
 
        res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return -1;
        }
 
        newparam = va_arg(aq, const char *);
        if (!newparam)  {
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return -1;
        }
        newval = va_arg(aq, const char *);
@@ -403,7 +402,7 @@ static int update_odbc(const char *database, const char *table, const char *keyf
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return -1;
        }
        
@@ -417,18 +416,18 @@ static int update_odbc(const char *database, const char *table, const char *keyf
                
        SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL);
 
-       res = odbc_smart_execute(obj, stmt);
+       res = ast_odbc_smart_execute(obj, stmt);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return -1;
        }
 
        res = SQLRowCount(stmt, &rowcount);
        SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-       odbc_release_obj(obj);
+       ast_odbc_release_obj(obj);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
@@ -443,15 +442,11 @@ static int update_odbc(const char *database, const char *table, const char *keyf
 
 struct config_odbc_obj {
        char *sql;
-       unsigned long id;
        unsigned long cat_metric;
-       unsigned long var_metric;
-       unsigned long commented;
-       char filename[128];
        char category[128];
        char var_name[128];
-       char var_val[128];
-       SQLINTEGER err;
+       char var_val[1024]; /* changed from 128 to 1024 via bug 8251 */
+       SQLLEN err;
 };
 
 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
@@ -475,27 +470,25 @@ static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
                return NULL;
        }
 
-       SQLBindCol(sth, 1, SQL_C_ULONG, &q->id, sizeof(q->id), &q->err);
-       SQLBindCol(sth, 2, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
-       SQLBindCol(sth, 3, SQL_C_ULONG, &q->var_metric, sizeof(q->var_metric), &q->err);
-       SQLBindCol(sth, 4, SQL_C_ULONG, &q->commented, sizeof(q->commented), &q->err);
-       SQLBindCol(sth, 5, SQL_C_CHAR, q->filename, sizeof(q->filename), &q->err);
-       SQLBindCol(sth, 6, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
-       SQLBindCol(sth, 7, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
-       SQLBindCol(sth, 8, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
+       SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
+       SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
+       SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
+       SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
 
        return sth;
 }
 
-static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg)
+static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
 {
        struct ast_variable *new_v;
        struct ast_category *cur_cat;
        int res = 0;
        struct odbc_obj *obj;
-       char sql[255] = "";
+       char sqlbuf[1024] = "";
+       char *sql = sqlbuf;
+       size_t sqlleft = sizeof(sqlbuf);
        unsigned int last_cat_metric = 0;
-       SQLSMALLINT rowcount=0;
+       SQLSMALLINT rowcount = 0;
        SQLHSTMT stmt;
        char last[128] = "";
        struct config_odbc_obj q;
@@ -505,18 +498,20 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        if (!file || !strcmp (file, "res_config_odbc.conf"))
                return NULL;            /* cant configure myself with myself ! */
 
-       obj = odbc_request_obj(database, 0);
+       obj = ast_odbc_request_obj(database, 0);
        if (!obj)
                return NULL;
 
-       snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE filename='%s' and commented=0 ORDER BY filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file);
-       q.sql = sql;
+       ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
+       ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
+       ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
+       q.sql = sqlbuf;
 
-       stmt = odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
+       stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
 
        if (!stmt) {
                ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
@@ -525,13 +520,13 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return NULL;
        }
 
        if (!rowcount) {
                ast_log(LOG_NOTICE, "found nothing\n");
-               odbc_release_obj(obj);
+               ast_odbc_release_obj(obj);
                return cfg;
        }
 
@@ -539,9 +534,9 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
 
        while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
                if (!strcmp (q.var_name, "#include")) {
-                       if (!ast_config_internal_load(q.var_val, cfg)) {
+                       if (!ast_config_internal_load(q.var_val, cfg, 0)) {
                                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-                               odbc_release_obj(obj);
+                               ast_odbc_release_obj(obj);
                                return NULL;
                        }
                        continue;
@@ -562,7 +557,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        }
 
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-       odbc_release_obj(obj);
+       ast_odbc_release_obj(obj);
        return cfg;
 }
 
@@ -574,16 +569,16 @@ static struct ast_config_engine odbc_engine = {
        .update_func = update_odbc
 };
 
-static int unload_module (void *mod)
+static int unload_module (void)
 {
-       ast_hangup_localusers(mod);
+       ast_module_user_hangup_all();
        ast_config_engine_deregister(&odbc_engine);
        if (option_verbose)
                ast_verbose("res_config_odbc unloaded.\n");
        return 0;
 }
 
-static int load_module (void *mod)
+static int load_module (void)
 {
        ast_config_engine_register(&odbc_engine);
        if (option_verbose)
@@ -591,14 +586,7 @@ static int load_module (void *mod)
        return 0;
 }
 
-static const char *description(void)
-{
-       return "ODBC Configuration";
-}
-
-static const char *key(void)
-{
-       return ASTERISK_GPL_KEY;
-}
-
-STD_MOD(MOD_0 | NO_USECOUNT | NO_UNLOAD, NULL, NULL, NULL);
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Realtime ODBC configuration",
+               .load = load_module,
+               .unload = unload_module,
+               );