Allow multiple rows to be fetched within the normal mode of operation.
authorTilghman Lesher <tilghman@meg.abyt.es>
Mon, 7 Sep 2009 17:15:37 +0000 (17:15 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Mon, 7 Sep 2009 17:15:37 +0000 (17:15 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@216846 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
configs/func_odbc.conf.sample
funcs/func_odbc.c

diff --git a/CHANGES b/CHANGES
index 533c45c..3a20677 100644 (file)
--- 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
 ------------------
index 1bc11be..fd528d2 100644 (file)
 ;              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
index c43417e..dbb5ace 100644 (file)
@@ -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 <func_odbc__200508@the-tilghman.com>
  *
@@ -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);
        }