diff options
author | tilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-12-28 20:13:00 +0000 |
---|---|---|
committer | tilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-12-28 20:13:00 +0000 |
commit | 8d086303b6b45b76b9d2af3f86d62868283cf71e (patch) | |
tree | 3ca90ba7ea94cb2257b6b48cb1862bc0be717475 /funcs/func_odbc.c | |
parent | 068fb38804250e64ced0d4e36e2cb35f3b85c008 (diff) |
Integrate functionality tested on svncommunity users back into trunk
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@49030 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'funcs/func_odbc.c')
-rw-r--r-- | funcs/func_odbc.c | 184 |
1 files changed, 130 insertions, 54 deletions
diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 529a342ff..bc50451f5 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <stdlib.h> #include <unistd.h> #include <string.h> +#include <errno.h> #include "asterisk/module.h" #include "asterisk/file.h" @@ -57,7 +58,8 @@ enum { struct acf_odbc_query { AST_LIST_ENTRY(acf_odbc_query) list; - char dsn[30]; + char readhandle[5][30]; + char writehandle[5][30]; char sql_read[2048]; char sql_write[2048]; unsigned int flags; @@ -96,7 +98,7 @@ static int acf_odbc_write(struct ast_channel *chan, char *cmd, char *s, const ch struct odbc_obj *obj; struct acf_odbc_query *query; char *t, buf[2048]="", varname[15]; - int i; + int i, dsn; AST_DECLARE_APP_ARGS(values, AST_APP_ARG(field)[100]; ); @@ -119,14 +121,6 @@ static int acf_odbc_write(struct ast_channel *chan, char *cmd, char *s, const ch return -1; } - obj = ast_odbc_request_obj(query->dsn, 0); - - if (!obj) { - ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", query->dsn); - AST_LIST_UNLOCK(&queries); - return -1; - } - /* Parse our arguments */ t = value ? ast_strdupa(value) : ""; @@ -169,7 +163,15 @@ static int acf_odbc_write(struct ast_channel *chan, char *cmd, char *s, const ch AST_LIST_UNLOCK(&queries); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, buf); + for (dsn = 0; dsn < 5; dsn++) { + if (!ast_strlen_zero(query->writehandle[dsn])) { + obj = ast_odbc_request_obj(query->writehandle[dsn], 0); + if (obj) + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, buf); + } + if (stmt) + break; + } if (stmt) { /* Rows affected */ @@ -195,14 +197,15 @@ static int acf_odbc_read(struct ast_channel *chan, char *cmd, char *s, char *buf { struct odbc_obj *obj; struct acf_odbc_query *query; - char sql[2048] = "", varname[15]; - int res, x, buflen = 0, escapecommas; + char sql[2048] = "", varname[15], colnames[2048] = ""; + int res, x, buflen = 0, escapecommas, dsn; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(field)[100]; ); SQLHSTMT stmt; SQLSMALLINT colcount=0; SQLLEN indicator; + SQLSMALLINT collength; AST_LIST_LOCK(&queries); AST_LIST_TRAVERSE(&queries, query, list) { @@ -217,14 +220,6 @@ static int acf_odbc_read(struct ast_channel *chan, char *cmd, char *s, char *buf return -1; } - obj = ast_odbc_request_obj(query->dsn, 0); - - if (!obj) { - ast_log(LOG_ERROR, "No such DSN registered (or out of connections): %s (check res_odbc.conf)\n", query->dsn); - AST_LIST_UNLOCK(&queries); - return -1; - } - AST_STANDARD_APP_ARGS(args, s); for (x = 0; x < args.argc; x++) { snprintf(varname, sizeof(varname), "ARG%d", x + 1); @@ -244,10 +239,20 @@ static int acf_odbc_read(struct ast_channel *chan, char *cmd, char *s, char *buf AST_LIST_UNLOCK(&queries); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql); + for (dsn = 0; dsn < 5; dsn++) { + if (!ast_strlen_zero(query->writehandle[dsn])) { + obj = ast_odbc_request_obj(query->writehandle[dsn], 0); + if (obj) + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql); + } + if (stmt) + break; + } if (!stmt) { - ast_odbc_release_obj(obj); + ast_log(LOG_ERROR, "Unable to execute query [%s]\n", sql); + if (obj) + ast_odbc_release_obj(obj); return -1; } @@ -278,8 +283,33 @@ static int acf_odbc_read(struct ast_channel *chan, char *cmd, char *s, char *buf } for (x = 0; x < colcount; x++) { - int i; - char coldata[256]; + int i, namelen; + char coldata[256], colname[256]; + + res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL); + if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { + snprintf(colname, sizeof(colname), "field%d", x); + } + + if (!ast_strlen_zero(colnames)) + strncat(colnames, ",", sizeof(colnames) - 1); + namelen = strlen(colnames); + + /* Copy data, encoding '\' and ',' for the argument parser */ + for (i = 0; i < sizeof(colname); i++) { + if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) { + colnames[namelen++] = '\\'; + } + colnames[namelen++] = colname[i]; + + if (namelen >= sizeof(colnames) - 2) { + colnames[namelen >= sizeof(colnames) ? sizeof(colnames) - 1 : namelen] = '\0'; + break; + } + + if (colname[i] == '\0') + break; + } buflen = strlen(buf); res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata, sizeof(coldata), &indicator); @@ -315,6 +345,8 @@ static int acf_odbc_read(struct ast_channel *chan, char *cmd, char *s, char *buf /* Trim trailing comma */ buf[buflen - 1] = '\0'; + pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); return 0; @@ -351,27 +383,68 @@ static struct ast_custom_function escape_function = { static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query) { const char *tmp; + int i; if (!cfg || !catg) { - return -1; + return EINVAL; } *query = ast_calloc(1, sizeof(struct acf_odbc_query)); if (! (*query)) - return -1; + return ENOMEM; + + if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) { + char *tmp2 = ast_strdupa(tmp); + AST_DECLARE_APP_ARGS(write, + AST_APP_ARG(dsn)[5]; + ); + AST_NONSTANDARD_APP_ARGS(write, tmp2, ','); + for (i = 0; i < 5; i++) { + if (!ast_strlen_zero(write.dsn[i])) + ast_copy_string((*query)->writehandle[i], write.dsn[i], sizeof((*query)->writehandle[i])); + } + } - if ((tmp = ast_variable_retrieve(cfg, catg, "dsn"))) { - ast_copy_string((*query)->dsn, tmp, sizeof((*query)->dsn)); + if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) { + char *tmp2 = ast_strdupa(tmp); + AST_DECLARE_APP_ARGS(read, + AST_APP_ARG(dsn)[5]; + ); + AST_NONSTANDARD_APP_ARGS(read, tmp2, ','); + for (i = 0; i < 5; i++) { + if (!ast_strlen_zero(read.dsn[i])) + ast_copy_string((*query)->readhandle[i], read.dsn[i], sizeof((*query)->readhandle[i])); + } } else { - return -1; - } + /* If no separate readhandle, then use the writehandle for reading */ + for (i = 0; i < 5; i++) { + if (!ast_strlen_zero((*query)->writehandle[i])) + ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i])); + } + } if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { + ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); + ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); + } else if ((tmp = ast_variable_retrieve(cfg, catg, "readsql"))) ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); + + if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) { + free(*query); + ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg); + return EINVAL; } if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { + ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); + } else if ((tmp = ast_variable_retrieve(cfg, catg, "writesql"))) + ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); + + if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) { + free(*query); + ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg); + return EINVAL; } /* Allow escaping of embedded commas in fields to be turned off */ @@ -384,7 +457,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function)); if (! (*query)->acf) { free(*query); - return -1; + return ENOMEM; } if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { @@ -396,7 +469,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu if (!((*query)->acf->name)) { free((*query)->acf); free(*query); - return -1; + return ENOMEM; } asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name); @@ -405,7 +478,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu free((char *)(*query)->acf->name); free((*query)->acf); free(*query); - return -1; + return ENOMEM; } (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; @@ -432,15 +505,21 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" "This function may only be set.\nSQL:\n%s\n", (*query)->sql_write); + } else { + free((char *)(*query)->acf->syntax); + free((char *)(*query)->acf->name); + free((*query)->acf); + free(*query); + ast_log(LOG_WARNING, "Section %s was found, but there was no SQL to execute. Ignoring.\n", catg); + return EINVAL; } - /* Could be out of memory, or could be we have neither sql_read nor sql_write */ if (! ((*query)->acf->desc)) { free((char *)(*query)->acf->syntax); free((char *)(*query)->acf->name); free((*query)->acf); free(*query); - return -1; + return ENOMEM; } if (ast_strlen_zero((*query)->sql_read)) { @@ -475,7 +554,7 @@ static int free_acf_query(struct acf_odbc_query *query) return 0; } -static int odbc_load_module(void) +static int load_module(void) { int res = 0; struct ast_config *cfg; @@ -494,10 +573,15 @@ static int odbc_load_module(void) catg; catg = ast_category_browse(cfg, catg)) { struct acf_odbc_query *query = NULL; - - if (init_acf_query(cfg, catg, &query)) { - ast_log(LOG_ERROR, "Out of memory\n"); - free_acf_query(query); + int err; + + if ((err = init_acf_query(cfg, catg, &query))) { + if (err == ENOMEM) + ast_log(LOG_ERROR, "Out of memory\n"); + else if (err == EINVAL) + ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg); + else + ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err); } else { AST_LIST_INSERT_HEAD(&queries, query, list); ast_custom_function_register(query->acf); @@ -505,15 +589,16 @@ static int odbc_load_module(void) } ast_config_destroy(cfg); - ast_custom_function_register(&escape_function); + res |= ast_custom_function_register(&escape_function); AST_LIST_UNLOCK(&queries); return res; } -static int odbc_unload_module(void) +static int unload_module(void) { struct acf_odbc_query *query; + int res = 0; AST_LIST_LOCK(&queries); while (!AST_LIST_EMPTY(&queries)) { @@ -522,10 +607,11 @@ static int odbc_unload_module(void) free_acf_query(query); } - ast_custom_function_unregister(&escape_function); + res |= ast_custom_function_unregister(&escape_function); /* Allow any threads waiting for this lock to pass (avoids a race) */ AST_LIST_UNLOCK(&queries); + usleep(1); AST_LIST_LOCK(&queries); AST_LIST_UNLOCK(&queries); @@ -572,16 +658,6 @@ reload_out: return res; } -static int unload_module(void) -{ - return odbc_unload_module(); -} - -static int load_module(void) -{ - return odbc_load_module(); -} - /* XXX need to revise usecount - set if query_lock is set */ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC lookups", |