From 40563b4d1c2b4fe90a20fd3240a5b29f5411648e Mon Sep 17 00:00:00 2001 From: tilghman Date: Mon, 7 Sep 2009 17:15:37 +0000 Subject: [PATCH] Allow multiple rows to be fetched within the normal mode of operation. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@216846 f38db490-d61c-443f-a65b-d21fe96a405b --- CHANGES | 4 +++ configs/func_odbc.conf.sample | 12 ++++++--- funcs/func_odbc.c | 51 +++++++++++++++++++++++++++++++---- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 533c45cac..3a2067737 100644 --- a/CHANGES +++ b/CHANGES @@ -105,6 +105,10 @@ Dialplan Functions channel, is one approach that will avoid conflicts. * Added new dialplan function MUTEAUDIO() for muting inbound and/or outbound audio in a channel. + * func_odbc now allows multiple row results to be retrieved without using + mode=multirow. If rowlimit is set, then additional rows may be retrieved + from the same query by using the name of the function which retrieved the + first row as an argument to ODBC_FETCH(). Dialplan Variables ------------------ diff --git a/configs/func_odbc.conf.sample b/configs/func_odbc.conf.sample index 1bc11be2e..fd528d216 100644 --- a/configs/func_odbc.conf.sample +++ b/configs/func_odbc.conf.sample @@ -62,10 +62,14 @@ ; query was initially performed. Additionally, as the results are ; associated with a channel, mode=multirow is incompatible with ; the global space. -; rowlimit An additional option for within mode=multirow, rowlimit limits -; the total number of rows which can be stored for that query. -; Otherwise, func_odbc will attempt to store all rows in the -; resultset, up to the maximum amount of memory. +; rowlimit Rowlimit limits the total number of rows which can be stored for +; that query. For mode=multirow, otherwise, func_odbc will +; attempt to store all rows in the resultset, up to the maximum +; amount of memory. In normal mode, rowlimit can be set to allow +; additional rows to be fetched, rather than just the first one. +; These additional rows can be returned by using the name of the +; function which was called to retrieve the first row as an +; argument to ODBC_FETCH(). ; ODBC_SQL - Allow an SQL statement to be built entirely in the dialplan diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index c43417e1c..dbb5ace45 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -2,7 +2,7 @@ * Asterisk -- An open source telephony toolkit. * * Copyright (c) 2005, 2006 Tilghman Lesher - * Copyright (c) 2008 Digium, Inc. + * Copyright (c) 2008, 2009 Digium, Inc. * * Tilghman Lesher * @@ -144,6 +144,8 @@ AST_THREADSTORAGE(sql2_buf); AST_THREADSTORAGE(coldata_buf); AST_THREADSTORAGE(colnames_buf); +static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len); + static void odbc_datastore_free(void *data) { struct odbc_datastore *result = data; @@ -388,7 +390,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha struct acf_odbc_query *query; char varname[15], rowcount[12] = "-1"; struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16); - int res, x, y, buflen = 0, escapecommas, rowlimit = 1, dsn, bogus_chan = 0; + int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn, bogus_chan = 0; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(field)[100]; ); @@ -460,13 +462,30 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha /* Save these flags, so we can release the lock */ escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS); if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) { - resultset = ast_calloc(1, sizeof(*resultset)); + if (!(resultset = ast_calloc(1, sizeof(*resultset)))) { + pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); + pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); + ast_autoservice_stop(chan); + return -1; + } AST_LIST_HEAD_INIT(resultset); if (query->rowlimit) { rowlimit = query->rowlimit; } else { rowlimit = INT_MAX; } + multirow = 1; + } else if (!bogus_chan) { + if (query->rowlimit > 1) { + rowlimit = query->rowlimit; + if (!(resultset = ast_calloc(1, sizeof(*resultset)))) { + pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); + pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); + ast_autoservice_stop(chan); + return -1; + } + AST_LIST_HEAD_INIT(resultset); + } } AST_RWLIST_UNLOCK(&queries); @@ -480,6 +499,8 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha if (stmt) { break; } + ast_odbc_release_obj(obj); + obj = NULL; } if (!stmt) { @@ -654,8 +675,22 @@ end_acf_read: if (resultset) { int uid; struct ast_datastore *odbc_store; - uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1; - snprintf(buf, len, "%d", uid); + if (multirow) { + uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1; + snprintf(buf, len, "%d", uid); + } else { + /* Name of the query is name of the resultset */ + ast_copy_string(buf, cmd, len); + + /* If there's one with the same name already, free it */ + ast_channel_lock(chan); + if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) { + ast_channel_datastore_remove(chan, odbc_store); + odbc_datastore_free(odbc_store->data); + ast_free(odbc_store); + } + ast_channel_unlock(chan); + } odbc_store = ast_datastore_alloc(&odbc_info, buf); if (!odbc_store) { ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n"); @@ -676,6 +711,12 @@ end_acf_read: SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); obj = NULL; + if (resultset && !multirow) { + /* Fetch the first resultset */ + if (!acf_fetch(chan, "", buf, buf, len)) { + buf[0] = '\0'; + } + } if (!bogus_chan) { ast_autoservice_stop(chan); }