Mon Mar 19 11:30:48 2012

Asterisk developer's documentation


func_odbc.c File Reference

ODBC lookups. More...

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/res_odbc.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/strings.h"

Go to the source code of this file.

Data Structures

struct  acf_odbc_query
struct  odbc_datastore
struct  odbc_datastore_row
struct  queries

Enumerations

enum  odbc_option_flags { OPT_ESCAPECOMMAS = (1 << 0), OPT_MULTIROW = (1 << 1) }

Functions

static void __init_coldata_buf (void)
static void __init_colnames_buf (void)
static void __init_sql2_buf (void)
static void __init_sql_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
static int acf_escape (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_fetch (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_odbc_read (struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
static int acf_odbc_write (struct ast_channel *chan, const char *cmd, char *s, const char *value)
static char * cli_odbc_read (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_odbc_write (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int exec_odbcfinish (struct ast_channel *chan, const char *data)
static int free_acf_query (struct acf_odbc_query *query)
static SQLHSTMT generic_execute (struct odbc_obj *obj, void *data)
static int init_acf_query (struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
static int load_module (void)
static void odbc_datastore_free (void *data)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ODBC lookups" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, }
static char * app_odbcfinish = "ODBCFinish"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_func_odbc []
static struct ast_threadstorage coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , }
static struct ast_threadstorage colnames_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_colnames_buf , .custom_init = NULL , }
static char * config = "func_odbc.conf"
static struct ast_custom_function escape_function
static struct ast_custom_function fetch_function
static struct ast_datastore_info odbc_info
static int resultcount = 0
static struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , }
static struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }


Detailed Description

ODBC lookups.

Author:
Tilghman Lesher <func_odbc__200508@the-tilghman.com>

Definition in file func_odbc.c.


Enumeration Type Documentation

enum odbc_option_flags

Enumerator:
OPT_ESCAPECOMMAS 
OPT_MULTIROW 

Definition at line 103 of file func_odbc.c.

00103                        {
00104    OPT_ESCAPECOMMAS =   (1 << 0),
00105    OPT_MULTIROW     =   (1 << 1),
00106 };


Function Documentation

static void __init_coldata_buf ( void   )  [static]

Definition at line 145 of file func_odbc.c.

00151 {

static void __init_colnames_buf ( void   )  [static]

Definition at line 146 of file func_odbc.c.

00151 {

static void __init_sql2_buf ( void   )  [static]

Definition at line 144 of file func_odbc.c.

00151 {

static void __init_sql_buf ( void   )  [static]

Definition at line 143 of file func_odbc.c.

00151 {

static void __reg_module ( void   )  [static]

Definition at line 1560 of file func_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 1560 of file func_odbc.c.

static int acf_escape ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 768 of file func_odbc.c.

00769 {
00770    char *out = buf;
00771 
00772    for (; *data && out - buf < len; data++) {
00773       if (*data == '\'') {
00774          *out = '\'';
00775          out++;
00776       }
00777       *out++ = *data;
00778    }
00779    *out = '\0';
00780 
00781    return 0;
00782 }

static int acf_fetch ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 790 of file func_odbc.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_datastore_free(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, odbc_datastore_row::data, ast_datastore::data, odbc_datastore_row::list, odbc_datastore::names, odbc_info, and pbx_builtin_setvar_helper().

00791 {
00792    struct ast_datastore *store;
00793    struct odbc_datastore *resultset;
00794    struct odbc_datastore_row *row;
00795 
00796    ast_channel_lock(chan);
00797    store = ast_channel_datastore_find(chan, &odbc_info, data);
00798    if (!store) {
00799       ast_channel_unlock(chan);
00800       pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
00801       return -1;
00802    }
00803    resultset = store->data;
00804    AST_LIST_LOCK(resultset);
00805    row = AST_LIST_REMOVE_HEAD(resultset, list);
00806    AST_LIST_UNLOCK(resultset);
00807    if (!row) {
00808       /* Cleanup datastore */
00809       ast_channel_datastore_remove(chan, store);
00810       ast_datastore_free(store);
00811       ast_channel_unlock(chan);
00812       pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
00813       return -1;
00814    }
00815    pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
00816    ast_channel_unlock(chan);
00817    ast_copy_string(buf, row->data, len);
00818    ast_free(row);
00819    pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
00820    return 0;
00821 }

static int acf_odbc_read ( struct ast_channel chan,
const char *  cmd,
char *  s,
char *  buf,
size_t  len 
) [static]

Definition at line 411 of file func_odbc.c.

References acf_odbc_query::acf, args, AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_unref, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc(), AST_LIST_HEAD_INIT, ast_log(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_reset(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strlen_zero(), ast_test_flag, colnames_buf, dsn, generic_execute(), LOG_ERROR, ast_custom_function::name, OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), acf_odbc_query::readhandle, acf_odbc_query::rowlimit, sql_buf, acf_odbc_query::sql_read, and status.

Referenced by init_acf_query().

00412 {
00413    struct odbc_obj *obj = NULL;
00414    struct acf_odbc_query *query;
00415    char varname[15], rowcount[12] = "-1";
00416    struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
00417    int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn, bogus_chan = 0;
00418    AST_DECLARE_APP_ARGS(args,
00419       AST_APP_ARG(field)[100];
00420    );
00421    SQLHSTMT stmt = NULL;
00422    SQLSMALLINT colcount=0;
00423    SQLLEN indicator;
00424    SQLSMALLINT collength;
00425    struct odbc_datastore *resultset = NULL;
00426    struct odbc_datastore_row *row = NULL;
00427    struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
00428    const char *status = "FAILURE";
00429 
00430    if (!sql || !colnames) {
00431       if (chan) {
00432          pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00433       }
00434       return -1;
00435    }
00436 
00437    ast_str_reset(colnames);
00438 
00439    AST_RWLIST_RDLOCK(&queries);
00440    AST_RWLIST_TRAVERSE(&queries, query, list) {
00441       if (!strcmp(query->acf->name, cmd)) {
00442          break;
00443       }
00444    }
00445 
00446    if (!query) {
00447       ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
00448       AST_RWLIST_UNLOCK(&queries);
00449       if (chan) {
00450          pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00451          pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00452       }
00453       return -1;
00454    }
00455 
00456    if (!chan) {
00457       if (!(chan = ast_dummy_channel_alloc())) {
00458          AST_RWLIST_UNLOCK(&queries);
00459          return -1;
00460       }
00461       bogus_chan = 1;
00462    }
00463 
00464    if (!bogus_chan) {
00465       ast_autoservice_start(chan);
00466    }
00467 
00468    AST_STANDARD_APP_ARGS(args, s);
00469    for (x = 0; x < args.argc; x++) {
00470       snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00471       pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
00472    }
00473 
00474    ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
00475 
00476    if (bogus_chan) {
00477       chan = ast_channel_unref(chan);
00478    } else {
00479       /* Restore prior values */
00480       for (x = 0; x < args.argc; x++) {
00481          snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00482          pbx_builtin_setvar_helper(chan, varname, NULL);
00483       }
00484    }
00485 
00486    /* Save these flags, so we can release the lock */
00487    escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
00488    if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
00489       if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
00490          pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00491          pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00492          ast_autoservice_stop(chan);
00493          return -1;
00494       }
00495       AST_LIST_HEAD_INIT(resultset);
00496       if (query->rowlimit) {
00497          rowlimit = query->rowlimit;
00498       } else {
00499          rowlimit = INT_MAX;
00500       }
00501       multirow = 1;
00502    } else if (!bogus_chan) {
00503       if (query->rowlimit > 1) {
00504          rowlimit = query->rowlimit;
00505          if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
00506             pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00507             pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00508             ast_autoservice_stop(chan);
00509             return -1;
00510          }
00511          AST_LIST_HEAD_INIT(resultset);
00512       }
00513    }
00514    AST_RWLIST_UNLOCK(&queries);
00515 
00516    for (dsn = 0; dsn < 5; dsn++) {
00517       if (!ast_strlen_zero(query->readhandle[dsn])) {
00518          obj = ast_odbc_request_obj(query->readhandle[dsn], 0);
00519          if (obj) {
00520             stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql));
00521          }
00522       }
00523       if (stmt) {
00524          break;
00525       }
00526       if (obj) {
00527          ast_odbc_release_obj(obj);
00528          obj = NULL;
00529       }
00530    }
00531 
00532    if (!stmt) {
00533       ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
00534       if (obj) {
00535          ast_odbc_release_obj(obj);
00536          obj = NULL;
00537       }
00538       if (!bogus_chan) {
00539          pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00540          ast_autoservice_stop(chan);
00541       }
00542       return -1;
00543    }
00544 
00545    res = SQLNumResultCols(stmt, &colcount);
00546    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00547       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
00548       SQLCloseCursor(stmt);
00549       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00550       ast_odbc_release_obj(obj);
00551       obj = NULL;
00552       if (!bogus_chan) {
00553          pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00554          ast_autoservice_stop(chan);
00555       }
00556       return -1;
00557    }
00558 
00559    res = SQLFetch(stmt);
00560    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00561       int res1 = -1;
00562       if (res == SQL_NO_DATA) {
00563          ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
00564          res1 = 0;
00565          buf[0] = '\0';
00566          ast_copy_string(rowcount, "0", sizeof(rowcount));
00567          status = "NODATA";
00568       } else {
00569          ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
00570          status = "FETCHERROR";
00571       }
00572       SQLCloseCursor(stmt);
00573       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00574       ast_odbc_release_obj(obj);
00575       obj = NULL;
00576       if (!bogus_chan) {
00577          pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00578          pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00579          ast_autoservice_stop(chan);
00580       }
00581       return res1;
00582    }
00583 
00584    status = "SUCCESS";
00585 
00586    for (y = 0; y < rowlimit; y++) {
00587       buf[0] = '\0';
00588       for (x = 0; x < colcount; x++) {
00589          int i;
00590          struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
00591          char *ptrcoldata;
00592 
00593          if (!coldata) {
00594             ast_free(resultset);
00595             SQLCloseCursor(stmt);
00596             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00597             ast_odbc_release_obj(obj);
00598             obj = NULL;
00599             if (!bogus_chan) {
00600                pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00601                ast_autoservice_stop(chan);
00602             }
00603             return -1;
00604          }
00605 
00606          if (y == 0) {
00607             char colname[256];
00608             SQLULEN maxcol = 0;
00609 
00610             res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
00611             ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x);
00612             if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
00613                snprintf(colname, sizeof(colname), "field%d", x);
00614             }
00615 
00616             ast_str_make_space(&coldata, maxcol + 1);
00617 
00618             if (ast_str_strlen(colnames)) {
00619                ast_str_append(&colnames, 0, ",");
00620             }
00621             ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
00622 
00623             if (resultset) {
00624                void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
00625                if (!tmp) {
00626                   ast_log(LOG_ERROR, "No space for a new resultset?\n");
00627                   ast_free(resultset);
00628                   SQLCloseCursor(stmt);
00629                   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00630                   ast_odbc_release_obj(obj);
00631                   obj = NULL;
00632                   if (!bogus_chan) {
00633                      pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00634                      pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00635                      ast_autoservice_stop(chan);
00636                   }
00637                   return -1;
00638                }
00639                resultset = tmp;
00640                strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
00641             }
00642          }
00643 
00644          buflen = strlen(buf);
00645          res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
00646          if (indicator == SQL_NULL_DATA) {
00647             ast_debug(3, "Got NULL data\n");
00648             ast_str_reset(coldata);
00649             res = SQL_SUCCESS;
00650          }
00651 
00652          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00653             ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
00654             y = -1;
00655             buf[0] = '\0';
00656             goto end_acf_read;
00657          }
00658 
00659          ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
00660 
00661          if (x) {
00662             buf[buflen++] = ',';
00663          }
00664 
00665          /* Copy data, encoding '\' and ',' for the argument parser */
00666          ptrcoldata = ast_str_buffer(coldata);
00667          for (i = 0; i < ast_str_strlen(coldata); i++) {
00668             if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
00669                buf[buflen++] = '\\';
00670             }
00671             buf[buflen++] = ptrcoldata[i];
00672 
00673             if (buflen >= len - 2) {
00674                break;
00675             }
00676 
00677             if (ptrcoldata[i] == '\0') {
00678                break;
00679             }
00680          }
00681 
00682          buf[buflen] = '\0';
00683          ast_debug(2, "buf is now set to '%s'\n", buf);
00684       }
00685       ast_debug(2, "buf is now set to '%s'\n", buf);
00686 
00687       if (resultset) {
00688          row = ast_calloc(1, sizeof(*row) + buflen + 1);
00689          if (!row) {
00690             ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
00691             status = "MEMERROR";
00692             goto end_acf_read;
00693          }
00694          strcpy((char *)row + sizeof(*row), buf);
00695          AST_LIST_INSERT_TAIL(resultset, row, list);
00696 
00697          /* Get next row */
00698          res = SQLFetch(stmt);
00699          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00700             if (res != SQL_NO_DATA) {
00701                ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
00702             }
00703             /* Number of rows in the resultset */
00704             y++;
00705             break;
00706          }
00707       }
00708    }
00709 
00710 end_acf_read:
00711    if (!bogus_chan) {
00712       snprintf(rowcount, sizeof(rowcount), "%d", y);
00713       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00714       pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00715       pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
00716       if (resultset) {
00717          int uid;
00718          struct ast_datastore *odbc_store;
00719          if (multirow) {
00720             uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
00721             snprintf(buf, len, "%d", uid);
00722          } else {
00723             /* Name of the query is name of the resultset */
00724             ast_copy_string(buf, cmd, len);
00725 
00726             /* If there's one with the same name already, free it */
00727             ast_channel_lock(chan);
00728             if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
00729                ast_channel_datastore_remove(chan, odbc_store);
00730                ast_datastore_free(odbc_store);
00731             }
00732             ast_channel_unlock(chan);
00733          }
00734          odbc_store = ast_datastore_alloc(&odbc_info, buf);
00735          if (!odbc_store) {
00736             ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel.  Results fail.\n");
00737             odbc_datastore_free(resultset);
00738             SQLCloseCursor(stmt);
00739             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00740             ast_odbc_release_obj(obj);
00741             obj = NULL;
00742             pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00743             ast_autoservice_stop(chan);
00744             return -1;
00745          }
00746          odbc_store->data = resultset;
00747          ast_channel_lock(chan);
00748          ast_channel_datastore_add(chan, odbc_store);
00749          ast_channel_unlock(chan);
00750       }
00751    }
00752    SQLCloseCursor(stmt);
00753    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00754    ast_odbc_release_obj(obj);
00755    obj = NULL;
00756    if (resultset && !multirow) {
00757       /* Fetch the first resultset */
00758       if (!acf_fetch(chan, "", buf, buf, len)) {
00759          buf[0] = '\0';
00760       }
00761    }
00762    if (!bogus_chan) {
00763       ast_autoservice_stop(chan);
00764    }
00765    return 0;
00766 }

static int acf_odbc_write ( struct ast_channel chan,
const char *  cmd,
char *  s,
const char *  value 
) [static]

Definition at line 206 of file func_odbc.c.

References acf_odbc_query::acf, args, AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_unref, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc(), ast_log(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj, ast_odbc_retrieve_transaction_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_make_space(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strdupa, ast_strlen_zero(), dsn, generic_execute(), acf_odbc_query::list, LOG_ERROR, LOG_WARNING, ast_custom_function::name, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), sql2_buf, sql_buf, acf_odbc_query::sql_insert, acf_odbc_query::sql_write, status, and acf_odbc_query::writehandle.

Referenced by init_acf_query().

00207 {
00208    struct odbc_obj *obj = NULL;
00209    struct acf_odbc_query *query;
00210    char *t, varname[15];
00211    int i, dsn, bogus_chan = 0;
00212    int transactional = 0;
00213    AST_DECLARE_APP_ARGS(values,
00214       AST_APP_ARG(field)[100];
00215    );
00216    AST_DECLARE_APP_ARGS(args,
00217       AST_APP_ARG(field)[100];
00218    );
00219    SQLHSTMT stmt = NULL;
00220    SQLLEN rows=0;
00221    struct ast_str *buf = ast_str_thread_get(&sql_buf, 16);
00222    struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16);
00223    const char *status = "FAILURE";
00224 
00225    if (!buf || !insertbuf) {
00226       return -1;
00227    }
00228 
00229    AST_RWLIST_RDLOCK(&queries);
00230    AST_RWLIST_TRAVERSE(&queries, query, list) {
00231       if (!strcmp(query->acf->name, cmd)) {
00232          break;
00233       }
00234    }
00235 
00236    if (!query) {
00237       ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
00238       AST_RWLIST_UNLOCK(&queries);
00239       if (chan) {
00240          pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00241       }
00242       return -1;
00243    }
00244 
00245    if (!chan) {
00246       if (!(chan = ast_dummy_channel_alloc())) {
00247          AST_RWLIST_UNLOCK(&queries);
00248          return -1;
00249       }
00250       bogus_chan = 1;
00251    }
00252 
00253    if (!bogus_chan) {
00254       ast_autoservice_start(chan);
00255    }
00256 
00257    ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
00258    ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
00259 
00260    /* Parse our arguments */
00261    t = value ? ast_strdupa(value) : "";
00262 
00263    if (!s || !t) {
00264       ast_log(LOG_ERROR, "Out of memory\n");
00265       AST_RWLIST_UNLOCK(&queries);
00266       if (!bogus_chan) {
00267          ast_autoservice_stop(chan);
00268          pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00269       } else {
00270          ast_channel_unref(chan);
00271       }
00272       return -1;
00273    }
00274 
00275    AST_STANDARD_APP_ARGS(args, s);
00276    for (i = 0; i < args.argc; i++) {
00277       snprintf(varname, sizeof(varname), "ARG%d", i + 1);
00278       pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
00279    }
00280 
00281    /* Parse values, just like arguments */
00282    AST_STANDARD_APP_ARGS(values, t);
00283    for (i = 0; i < values.argc; i++) {
00284       snprintf(varname, sizeof(varname), "VAL%d", i + 1);
00285       pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
00286    }
00287 
00288    /* Additionally set the value as a whole (but push an empty string if value is NULL) */
00289    pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
00290 
00291    ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
00292    ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
00293 
00294    if (bogus_chan) {
00295       chan = ast_channel_unref(chan);
00296    } else {
00297       /* Restore prior values */
00298       for (i = 0; i < args.argc; i++) {
00299          snprintf(varname, sizeof(varname), "ARG%d", i + 1);
00300          pbx_builtin_setvar_helper(chan, varname, NULL);
00301       }
00302 
00303       for (i = 0; i < values.argc; i++) {
00304          snprintf(varname, sizeof(varname), "VAL%d", i + 1);
00305          pbx_builtin_setvar_helper(chan, varname, NULL);
00306       }
00307       pbx_builtin_setvar_helper(chan, "VALUE", NULL);
00308    }
00309 
00310    /*!\note
00311     * Okay, this part is confusing.  Transactions belong to a single database
00312     * handle.  Therefore, when working with transactions, we CANNOT failover
00313     * to multiple DSNs.  We MUST have a single handle all the way through the
00314     * transaction, or else we CANNOT enforce atomicity.
00315     */
00316    for (dsn = 0; dsn < 5; dsn++) {
00317       if (!ast_strlen_zero(query->writehandle[dsn])) {
00318          if (transactional) {
00319             /* This can only happen second time through or greater. */
00320             ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
00321          }
00322 
00323          if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
00324             transactional = 1;
00325          } else {
00326             obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
00327             transactional = 0;
00328          }
00329 
00330          if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
00331             break;
00332          }
00333 
00334          if (obj && !transactional) {
00335             ast_odbc_release_obj(obj);
00336             obj = NULL;
00337          }
00338       }
00339    }
00340 
00341    if (stmt) {
00342       SQLRowCount(stmt, &rows);
00343    }
00344 
00345    if (stmt && rows == 0 && ast_str_strlen(insertbuf) != 0) {
00346       SQLCloseCursor(stmt);
00347       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00348       if (obj && !transactional) {
00349          ast_odbc_release_obj(obj);
00350          obj = NULL;
00351       }
00352 
00353       for (transactional = 0, dsn = 0; dsn < 5; dsn++) {
00354          if (!ast_strlen_zero(query->writehandle[dsn])) {
00355             if (transactional) {
00356                /* This can only happen second time through or greater. */
00357                ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
00358             } else if (obj) {
00359                ast_odbc_release_obj(obj);
00360                obj = NULL;
00361             }
00362 
00363             if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
00364                transactional = 1;
00365             } else {
00366                obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
00367                transactional = 0;
00368             }
00369             if (obj) {
00370                stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
00371             }
00372          }
00373          if (stmt) {
00374             status = "FAILOVER";
00375             SQLRowCount(stmt, &rows);
00376             break;
00377          }
00378       }
00379    } else if (stmt) {
00380       status = "SUCCESS";
00381    }
00382 
00383    AST_RWLIST_UNLOCK(&queries);
00384 
00385    /* Output the affected rows, for all cases.  In the event of failure, we
00386     * flag this as -1 rows.  Note that this is different from 0 affected rows
00387     * which would be the case if we succeeded in our query, but the values did
00388     * not change. */
00389    if (!bogus_chan) {
00390       snprintf(varname, sizeof(varname), "%d", (int)rows);
00391       pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
00392       pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00393    }
00394 
00395    if (stmt) {
00396       SQLCloseCursor(stmt);
00397       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00398    }
00399    if (obj && !transactional) {
00400       ast_odbc_release_obj(obj);
00401       obj = NULL;
00402    }
00403 
00404    if (!bogus_chan) {
00405       ast_autoservice_stop(chan);
00406    }
00407 
00408    return 0;
00409 }

static char* cli_odbc_read ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1078 of file func_odbc.c.

References acf_odbc_query::acf, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, ast_cli_args::n, ast_custom_function::name, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01079 {
01080    AST_DECLARE_APP_ARGS(args,
01081       AST_APP_ARG(field)[100];
01082    );
01083    struct ast_str *sql;
01084    char *char_args, varname[10];
01085    struct acf_odbc_query *query;
01086    struct ast_channel *chan;
01087    int i;
01088 
01089    switch (cmd) {
01090    case CLI_INIT:
01091       e->command = "odbc read";
01092       e->usage =
01093          "Usage: odbc read <name> <args> [exec]\n"
01094          "       Evaluates the SQL provided in the ODBC function <name>, and\n"
01095          "       optionally executes the function.  This function is intended for\n"
01096          "       testing purposes.  Remember to quote arguments containing spaces.\n";
01097       return NULL;
01098    case CLI_GENERATE:
01099       if (a->pos == 2) {
01100          int wordlen = strlen(a->word), which = 0;
01101          /* Complete function name */
01102          AST_RWLIST_RDLOCK(&queries);
01103          AST_RWLIST_TRAVERSE(&queries, query, list) {
01104             if (!strncasecmp(query->acf->name, a->word, wordlen)) {
01105                if (++which > a->n) {
01106                   char *res = ast_strdup(query->acf->name);
01107                   AST_RWLIST_UNLOCK(&queries);
01108                   return res;
01109                }
01110             }
01111          }
01112          AST_RWLIST_UNLOCK(&queries);
01113          return NULL;
01114       } else if (a->pos == 4) {
01115          return a->n == 0 ? ast_strdup("exec") : NULL;
01116       } else {
01117          return NULL;
01118       }
01119    }
01120 
01121    if (a->argc < 4 || a->argc > 5) {
01122       return CLI_SHOWUSAGE;
01123    }
01124 
01125    sql = ast_str_thread_get(&sql_buf, 16);
01126    if (!sql) {
01127       return CLI_FAILURE;
01128    }
01129 
01130    AST_RWLIST_RDLOCK(&queries);
01131    AST_RWLIST_TRAVERSE(&queries, query, list) {
01132       if (!strcmp(query->acf->name, a->argv[2])) {
01133          break;
01134       }
01135    }
01136 
01137    if (!query) {
01138       ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
01139       AST_RWLIST_UNLOCK(&queries);
01140       return CLI_SHOWUSAGE;
01141    }
01142 
01143    if (ast_strlen_zero(query->sql_read)) {
01144       ast_cli(a->fd, "The function %s has no readsql parameter.\n", a->argv[2]);
01145       AST_RWLIST_UNLOCK(&queries);
01146       return CLI_SUCCESS;
01147    }
01148 
01149    ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
01150 
01151    /* Evaluate function */
01152    char_args = ast_strdupa(a->argv[3]);
01153 
01154    chan = ast_dummy_channel_alloc();
01155    if (!chan) {
01156       AST_RWLIST_UNLOCK(&queries);
01157       return CLI_FAILURE;
01158    }
01159 
01160    AST_STANDARD_APP_ARGS(args, char_args);
01161    for (i = 0; i < args.argc; i++) {
01162       snprintf(varname, sizeof(varname), "ARG%d", i + 1);
01163       pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
01164    }
01165 
01166    ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
01167    chan = ast_channel_unref(chan);
01168 
01169    if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
01170       /* Execute the query */
01171       struct odbc_obj *obj = NULL;
01172       int dsn, executed = 0;
01173       SQLHSTMT stmt;
01174       int rows = 0, res, x;
01175       SQLSMALLINT colcount = 0, collength;
01176       SQLLEN indicator;
01177       struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
01178       char colname[256];
01179       SQLULEN maxcol;
01180 
01181       if (!coldata) {
01182          AST_RWLIST_UNLOCK(&queries);
01183          return CLI_SUCCESS;
01184       }
01185 
01186       for (dsn = 0; dsn < 5; dsn++) {
01187          if (ast_strlen_zero(query->readhandle[dsn])) {
01188             continue;
01189          }
01190          ast_debug(1, "Found handle %s\n", query->readhandle[dsn]);
01191          if (!(obj = ast_odbc_request_obj(query->readhandle[dsn], 0))) {
01192             continue;
01193          }
01194 
01195          ast_debug(1, "Got obj\n");
01196          if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
01197             ast_odbc_release_obj(obj);
01198             obj = NULL;
01199             continue;
01200          }
01201 
01202          executed = 1;
01203 
01204          res = SQLNumResultCols(stmt, &colcount);
01205          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01206             ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
01207             SQLCloseCursor(stmt);
01208             SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01209             ast_odbc_release_obj(obj);
01210             obj = NULL;
01211             AST_RWLIST_UNLOCK(&queries);
01212             return CLI_SUCCESS;
01213          }
01214 
01215          res = SQLFetch(stmt);
01216          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01217             SQLCloseCursor(stmt);
01218             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01219             ast_odbc_release_obj(obj);
01220             obj = NULL;
01221             if (res == SQL_NO_DATA) {
01222                ast_cli(a->fd, "Returned %d rows.  Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql));
01223                break;
01224             } else {
01225                ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
01226             }
01227             AST_RWLIST_UNLOCK(&queries);
01228             return CLI_SUCCESS;
01229          }
01230          for (;;) {
01231             for (x = 0; x < colcount; x++) {
01232                maxcol = 0;
01233 
01234                res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
01235                if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
01236                   snprintf(colname, sizeof(colname), "field%d", x);
01237                }
01238 
01239                res = ast_odbc_ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator);
01240                if (indicator == SQL_NULL_DATA) {
01241                   ast_str_set(&coldata, 0, "(nil)");
01242                   res = SQL_SUCCESS;
01243                }
01244 
01245                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01246                   ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
01247                   SQLCloseCursor(stmt);
01248                   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01249                   ast_odbc_release_obj(obj);
01250                   obj = NULL;
01251                   AST_RWLIST_UNLOCK(&queries);
01252                   return CLI_SUCCESS;
01253                }
01254 
01255                ast_cli(a->fd, "%-20.20s  %s\n", colname, ast_str_buffer(coldata));
01256             }
01257             rows++;
01258 
01259             /* Get next row */
01260             res = SQLFetch(stmt);
01261             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01262                break;
01263             }
01264             ast_cli(a->fd, "%-20.20s  %s\n", "----------", "----------");
01265          }
01266          SQLCloseCursor(stmt);
01267          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01268          ast_odbc_release_obj(obj);
01269          obj = NULL;
01270          ast_cli(a->fd, "Returned %d row%s.  Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn, query->readhandle[dsn]);
01271          break;
01272       }
01273       if (obj) {
01274          ast_odbc_release_obj(obj);
01275          obj = NULL;
01276       }
01277 
01278       if (!executed) {
01279          ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
01280       }
01281    } else { /* No execution, just print out the resulting SQL */
01282       ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
01283    }
01284    AST_RWLIST_UNLOCK(&queries);
01285    return CLI_SUCCESS;
01286 }

static char* cli_odbc_write ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1288 of file func_odbc.c.

References acf_odbc_query::acf, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, ast_cli_args::n, ast_custom_function::name, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01289 {
01290    AST_DECLARE_APP_ARGS(values,
01291       AST_APP_ARG(field)[100];
01292    );
01293    AST_DECLARE_APP_ARGS(args,
01294       AST_APP_ARG(field)[100];
01295    );
01296    struct ast_str *sql;
01297    char *char_args, *char_values, varname[10];
01298    struct acf_odbc_query *query;
01299    struct ast_channel *chan;
01300    int i;
01301 
01302    switch (cmd) {
01303    case CLI_INIT:
01304       e->command = "odbc write";
01305       e->usage =
01306          "Usage: odbc write <name> <args> <value> [exec]\n"
01307          "       Evaluates the SQL provided in the ODBC function <name>, and\n"
01308          "       optionally executes the function.  This function is intended for\n"
01309          "       testing purposes.  Remember to quote arguments containing spaces.\n";
01310       return NULL;
01311    case CLI_GENERATE:
01312       if (a->pos == 2) {
01313          int wordlen = strlen(a->word), which = 0;
01314          /* Complete function name */
01315          AST_RWLIST_RDLOCK(&queries);
01316          AST_RWLIST_TRAVERSE(&queries, query, list) {
01317             if (!strncasecmp(query->acf->name, a->word, wordlen)) {
01318                if (++which > a->n) {
01319                   char *res = ast_strdup(query->acf->name);
01320                   AST_RWLIST_UNLOCK(&queries);
01321                   return res;
01322                }
01323             }
01324          }
01325          AST_RWLIST_UNLOCK(&queries);
01326          return NULL;
01327       } else if (a->pos == 5) {
01328          return a->n == 0 ? ast_strdup("exec") : NULL;
01329       } else {
01330          return NULL;
01331       }
01332    }
01333 
01334    if (a->argc < 5 || a->argc > 6) {
01335       return CLI_SHOWUSAGE;
01336    }
01337 
01338    sql = ast_str_thread_get(&sql_buf, 16);
01339    if (!sql) {
01340       return CLI_FAILURE;
01341    }
01342 
01343    AST_RWLIST_RDLOCK(&queries);
01344    AST_RWLIST_TRAVERSE(&queries, query, list) {
01345       if (!strcmp(query->acf->name, a->argv[2])) {
01346          break;
01347       }
01348    }
01349 
01350    if (!query) {
01351       ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
01352       AST_RWLIST_UNLOCK(&queries);
01353       return CLI_SHOWUSAGE;
01354    }
01355 
01356    if (ast_strlen_zero(query->sql_write)) {
01357       ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
01358       AST_RWLIST_UNLOCK(&queries);
01359       return CLI_SUCCESS;
01360    }
01361 
01362    ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
01363 
01364    /* Evaluate function */
01365    char_args = ast_strdupa(a->argv[3]);
01366    char_values = ast_strdupa(a->argv[4]);
01367 
01368    chan = ast_dummy_channel_alloc();
01369    if (!chan) {
01370       AST_RWLIST_UNLOCK(&queries);
01371       return CLI_FAILURE;
01372    }
01373 
01374    AST_STANDARD_APP_ARGS(args, char_args);
01375    for (i = 0; i < args.argc; i++) {
01376       snprintf(varname, sizeof(varname), "ARG%d", i + 1);
01377       pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
01378    }
01379 
01380    /* Parse values, just like arguments */
01381    AST_STANDARD_APP_ARGS(values, char_values);
01382    for (i = 0; i < values.argc; i++) {
01383       snprintf(varname, sizeof(varname), "VAL%d", i + 1);
01384       pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
01385    }
01386 
01387    /* Additionally set the value as a whole (but push an empty string if value is NULL) */
01388    pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
01389    ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
01390    ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
01391 
01392    chan = ast_channel_unref(chan);
01393 
01394    if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
01395       /* Execute the query */
01396       struct odbc_obj *obj = NULL;
01397       int dsn, executed = 0;
01398       SQLHSTMT stmt;
01399       SQLLEN rows = -1;
01400 
01401       for (dsn = 0; dsn < 5; dsn++) {
01402          if (ast_strlen_zero(query->writehandle[dsn])) {
01403             continue;
01404          }
01405          if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) {
01406             continue;
01407          }
01408          if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
01409             ast_odbc_release_obj(obj);
01410             obj = NULL;
01411             continue;
01412          }
01413 
01414          SQLRowCount(stmt, &rows);
01415          SQLCloseCursor(stmt);
01416          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01417          ast_odbc_release_obj(obj);
01418          obj = NULL;
01419          ast_cli(a->fd, "Affected %d rows.  Query executed on handle %d [%s]\n", (int)rows, dsn, query->writehandle[dsn]);
01420          executed = 1;
01421          break;
01422       }
01423 
01424       if (!executed) {
01425          ast_cli(a->fd, "Failed to execute query.\n");
01426       }
01427    } else { /* No execution, just print out the resulting SQL */
01428       ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
01429    }
01430    AST_RWLIST_UNLOCK(&queries);
01431    return CLI_SUCCESS;
01432 }

static int exec_odbcfinish ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 831 of file func_odbc.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), and odbc_info.

Referenced by load_module().

00832 {
00833    struct ast_datastore *store;
00834 
00835    ast_channel_lock(chan);
00836    store = ast_channel_datastore_find(chan, &odbc_info, data);
00837    if (store) {
00838       ast_channel_datastore_remove(chan, store);
00839       ast_datastore_free(store);
00840    }
00841    ast_channel_unlock(chan);
00842    return 0;
00843 }

static int free_acf_query ( struct acf_odbc_query query  )  [static]

Definition at line 1064 of file func_odbc.c.

References acf_odbc_query::acf, ast_free, ast_string_field_free_memory, and ast_custom_function::name.

Referenced by reload(), and unload_module().

01065 {
01066    if (query) {
01067       if (query->acf) {
01068          if (query->acf->name)
01069             ast_free((char *)query->acf->name);
01070          ast_string_field_free_memory(query->acf);
01071          ast_free(query->acf);
01072       }
01073       ast_free(query);
01074    }
01075    return 0;
01076 }

static SQLHSTMT generic_execute ( struct odbc_obj obj,
void *  data 
) [static]

Definition at line 163 of file func_odbc.c.

References ast_log(), odbc_obj::con, and LOG_WARNING.

Referenced by acf_odbc_read(), and acf_odbc_write().

00164 {
00165    int res;
00166    char *sql = data;
00167    SQLHSTMT stmt;
00168 
00169    res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00170    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00171       ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
00172       return NULL;
00173    }
00174 
00175    res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS);
00176    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00177       if (res == SQL_ERROR) {
00178          int i;
00179          SQLINTEGER nativeerror=0, numfields=0;
00180          SQLSMALLINT diagbytes=0;
00181          unsigned char state[10], diagnostic[256];
00182 
00183          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00184          for (i = 0; i < numfields; i++) {
00185             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00186             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00187             if (i > 10) {
00188                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00189                break;
00190             }
00191          }
00192       }
00193 
00194       ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
00195       SQLCloseCursor(stmt);
00196       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00197       return NULL;
00198    }
00199 
00200    return stmt;
00201 }

static int init_acf_query ( struct ast_config cfg,
char *  catg,
struct acf_odbc_query **  query 
) [static]

Definition at line 845 of file func_odbc.c.

References acf_odbc_query::acf, acf_odbc_read(), acf_odbc_write(), asprintf, AST_APP_ARG, ast_calloc, ast_clear_flag, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_false(), ast_free, ast_log(), ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_string_field_build, ast_string_field_free_memory, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_retrieve(), desc, dsn, errno, OPT_ESCAPECOMMAS, OPT_MULTIROW, ast_custom_function::read, and synopsis.

Referenced by load_module(), and reload().

00846 {
00847    const char *tmp;
00848    int i;
00849 
00850    if (!cfg || !catg) {
00851       return EINVAL;
00852    }
00853 
00854    *query = ast_calloc(1, sizeof(struct acf_odbc_query));
00855    if (! (*query))
00856       return ENOMEM;
00857 
00858    if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
00859       char *tmp2 = ast_strdupa(tmp);
00860       AST_DECLARE_APP_ARGS(writeconf,
00861          AST_APP_ARG(dsn)[5];
00862       );
00863       AST_STANDARD_APP_ARGS(writeconf, tmp2);
00864       for (i = 0; i < 5; i++) {
00865          if (!ast_strlen_zero(writeconf.dsn[i]))
00866             ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
00867       }
00868    }
00869 
00870    if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
00871       char *tmp2 = ast_strdupa(tmp);
00872       AST_DECLARE_APP_ARGS(readconf,
00873          AST_APP_ARG(dsn)[5];
00874       );
00875       AST_STANDARD_APP_ARGS(readconf, tmp2);
00876       for (i = 0; i < 5; i++) {
00877          if (!ast_strlen_zero(readconf.dsn[i]))
00878             ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
00879       }
00880    } else {
00881       /* If no separate readhandle, then use the writehandle for reading */
00882       for (i = 0; i < 5; i++) {
00883          if (!ast_strlen_zero((*query)->writehandle[i]))
00884             ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
00885       }
00886    }
00887 
00888    if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")))
00889       ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00890    else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) {
00891       ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s.  Please use 'readsql' instead.\n", catg);
00892       ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00893    }
00894 
00895    if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) {
00896       ast_free(*query);
00897       *query = NULL;
00898       ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
00899       return EINVAL;
00900    }
00901 
00902    if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")))
00903       ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00904    else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) {
00905       ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s.  Please use 'writesql' instead.\n", catg);
00906       ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00907    }
00908 
00909    if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) {
00910       ast_free(*query);
00911       *query = NULL;
00912       ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
00913       return EINVAL;
00914    }
00915 
00916    if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
00917       ast_copy_string((*query)->sql_insert, tmp, sizeof((*query)->sql_insert));
00918    }
00919 
00920    /* Allow escaping of embedded commas in fields to be turned off */
00921    ast_set_flag((*query), OPT_ESCAPECOMMAS);
00922    if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
00923       if (ast_false(tmp))
00924          ast_clear_flag((*query), OPT_ESCAPECOMMAS);
00925    }
00926 
00927    if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
00928       if (strcasecmp(tmp, "multirow") == 0)
00929          ast_set_flag((*query), OPT_MULTIROW);
00930       if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
00931          sscanf(tmp, "%30d", &((*query)->rowlimit));
00932    }
00933 
00934    (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
00935    if (! (*query)->acf) {
00936       ast_free(*query);
00937       *query = NULL;
00938       return ENOMEM;
00939    }
00940    if (ast_string_field_init((*query)->acf, 128)) {
00941       ast_free((*query)->acf);
00942       ast_free(*query);
00943       *query = NULL;
00944       return ENOMEM;
00945    }
00946 
00947    if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
00948       if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
00949          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00950       }
00951    } else {
00952       if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
00953          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00954       }
00955    }
00956 
00957    if (!((*query)->acf->name)) {
00958       ast_string_field_free_memory((*query)->acf);
00959       ast_free((*query)->acf);
00960       ast_free(*query);
00961       *query = NULL;
00962       return ENOMEM;
00963    }
00964 
00965    if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
00966       ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
00967    } else {
00968       ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
00969    }
00970 
00971    if (ast_strlen_zero((*query)->acf->syntax)) {
00972       ast_free((char *)(*query)->acf->name);
00973       ast_string_field_free_memory((*query)->acf);
00974       ast_free((*query)->acf);
00975       ast_free(*query);
00976       *query = NULL;
00977       return ENOMEM;
00978    }
00979 
00980    if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
00981       ast_string_field_set((*query)->acf, synopsis, tmp);
00982    } else {
00983       ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
00984    }
00985 
00986    if (ast_strlen_zero((*query)->acf->synopsis)) {
00987       ast_free((char *)(*query)->acf->name);
00988       ast_string_field_free_memory((*query)->acf);
00989       ast_free((*query)->acf);
00990       ast_free(*query);
00991       *query = NULL;
00992       return ENOMEM;
00993    }
00994 
00995    if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) {
00996       ast_string_field_build((*query)->acf, desc,
00997                "Runs the following query, as defined in func_odbc.conf, performing\n"
00998                   "substitution of the arguments into the query as specified by ${ARG1},\n"
00999                "${ARG2}, ... ${ARGn}.  When setting the function, the values are provided\n"
01000                "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
01001                "%s"
01002                "\nRead:\n%s\n\nWrite:\n%s\n%s%s%s",
01003                ast_strlen_zero((*query)->sql_insert) ? "" :
01004                   "If the write query affects no rows, the insert query will be\n"
01005                   "performed.\n",
01006                (*query)->sql_read,
01007                (*query)->sql_write,
01008                ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n",
01009                ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
01010                ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
01011    } else if (!ast_strlen_zero((*query)->sql_read)) {
01012       ast_string_field_build((*query)->acf, desc,
01013                   "Runs the following query, as defined in func_odbc.conf, performing\n"
01014                      "substitution of the arguments into the query as specified by ${ARG1},\n"
01015                   "${ARG2}, ... ${ARGn}.  This function may only be read, not set.\n\nSQL:\n%s\n",
01016                   (*query)->sql_read);
01017    } else if (!ast_strlen_zero((*query)->sql_write)) {
01018       ast_string_field_build((*query)->acf, desc,  
01019                "Runs the following query, as defined in func_odbc.conf, performing\n"
01020                   "substitution of the arguments into the query as specified by ${ARG1},\n"
01021                "${ARG2}, ... ${ARGn}.  The values are provided either in whole as\n"
01022                "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
01023                "This function may only be set.\n%sSQL:\n%s\n%s%s%s",
01024                ast_strlen_zero((*query)->sql_insert) ? "" :
01025                   "If the write query affects no rows, the insert query will be\n"
01026                   "performed.\n",
01027                (*query)->sql_write,
01028                ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n",
01029                ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
01030                ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
01031    } else {
01032       ast_string_field_free_memory((*query)->acf);
01033       ast_free((char *)(*query)->acf->name);
01034       ast_free((*query)->acf);
01035       ast_free(*query);
01036       ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute.  Ignoring.\n", catg);
01037       return EINVAL;
01038    }
01039 
01040    if (ast_strlen_zero((*query)->acf->desc)) {
01041       ast_string_field_free_memory((*query)->acf);
01042       ast_free((char *)(*query)->acf->name);
01043       ast_free((*query)->acf);
01044       ast_free(*query);
01045       *query = NULL;
01046       return ENOMEM;
01047    }
01048 
01049    if (ast_strlen_zero((*query)->sql_read)) {
01050       (*query)->acf->read = NULL;
01051    } else {
01052       (*query)->acf->read = acf_odbc_read;
01053    }
01054 
01055    if (ast_strlen_zero((*query)->sql_write)) {
01056       (*query)->acf->write = NULL;
01057    } else {
01058       (*query)->acf->write = acf_odbc_write;
01059    }
01060 
01061    return 0;
01062 }

static int load_module ( void   )  [static]

Definition at line 1439 of file func_odbc.c.

References ARRAY_LEN, ast_category_browse(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application_xml, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, cli_func_odbc, config_flags, CONFIG_STATUS_FILEINVALID, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), and LOG_NOTICE.

01440 {
01441    int res = 0;
01442    struct ast_config *cfg;
01443    char *catg;
01444    struct ast_flags config_flags = { 0 };
01445 
01446    res |= ast_custom_function_register(&fetch_function);
01447    res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish);
01448    AST_RWLIST_WRLOCK(&queries);
01449 
01450    cfg = ast_config_load(config, config_flags);
01451    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
01452       ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
01453       AST_RWLIST_UNLOCK(&queries);
01454       return AST_MODULE_LOAD_DECLINE;
01455    }
01456 
01457    for (catg = ast_category_browse(cfg, NULL);
01458         catg;
01459         catg = ast_category_browse(cfg, catg)) {
01460       struct acf_odbc_query *query = NULL;
01461       int err;
01462 
01463       if ((err = init_acf_query(cfg, catg, &query))) {
01464          if (err == ENOMEM)
01465             ast_log(LOG_ERROR, "Out of memory\n");
01466          else if (err == EINVAL)
01467             ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
01468          else
01469             ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
01470       } else {
01471          AST_RWLIST_INSERT_HEAD(&queries, query, list);
01472          ast_custom_function_register(query->acf);
01473       }
01474    }
01475 
01476    ast_config_destroy(cfg);
01477    res |= ast_custom_function_register(&escape_function);
01478    ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
01479 
01480    AST_RWLIST_UNLOCK(&queries);
01481    return res;
01482 }

static void odbc_datastore_free ( void *  data  )  [static]

Definition at line 150 of file func_odbc.c.

References ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and acf_odbc_query::list.

00151 {
00152    struct odbc_datastore *result = data;
00153    struct odbc_datastore_row *row;
00154    AST_LIST_LOCK(result);
00155    while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
00156       ast_free(row);
00157    }
00158    AST_LIST_UNLOCK(result);
00159    AST_LIST_HEAD_DESTROY(result);
00160    ast_free(result);
00161 }

static int reload ( void   )  [static]

Definition at line 1510 of file func_odbc.c.

References acf_odbc_query::acf, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_custom_function_unregister(), ast_log(), AST_RWLIST_EMPTY, AST_RWLIST_INSERT_HEAD, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, free_acf_query(), and init_acf_query().

01511 {
01512    int res = 0;
01513    struct ast_config *cfg;
01514    struct acf_odbc_query *oldquery;
01515    char *catg;
01516    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
01517 
01518    cfg = ast_config_load(config, config_flags);
01519    if (cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
01520       return 0;
01521 
01522    AST_RWLIST_WRLOCK(&queries);
01523 
01524    while (!AST_RWLIST_EMPTY(&queries)) {
01525       oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
01526       ast_custom_function_unregister(oldquery->acf);
01527       free_acf_query(oldquery);
01528    }
01529 
01530    if (!cfg) {
01531       ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
01532       goto reload_out;
01533    }
01534 
01535    for (catg = ast_category_browse(cfg, NULL);
01536         catg;
01537         catg = ast_category_browse(cfg, catg)) {
01538       struct acf_odbc_query *query = NULL;
01539 
01540       if (init_acf_query(cfg, catg, &query)) {
01541          ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
01542       } else {
01543          AST_RWLIST_INSERT_HEAD(&queries, query, list);
01544          ast_custom_function_register(query->acf);
01545       }
01546    }
01547 
01548    ast_config_destroy(cfg);
01549 reload_out:
01550    AST_RWLIST_UNLOCK(&queries);
01551    return res;
01552 }

static int unload_module ( void   )  [static]

Definition at line 1484 of file func_odbc.c.

References acf_odbc_query::acf, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), AST_RWLIST_EMPTY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_unregister_application(), cli_func_odbc, escape_function, fetch_function, free_acf_query(), and acf_odbc_query::list.

01485 {
01486    struct acf_odbc_query *query;
01487    int res = 0;
01488 
01489    AST_RWLIST_WRLOCK(&queries);
01490    while (!AST_RWLIST_EMPTY(&queries)) {
01491       query = AST_RWLIST_REMOVE_HEAD(&queries, list);
01492       ast_custom_function_unregister(query->acf);
01493       free_acf_query(query);
01494    }
01495 
01496    res |= ast_custom_function_unregister(&escape_function);
01497    res |= ast_custom_function_unregister(&fetch_function);
01498    res |= ast_unregister_application(app_odbcfinish);
01499    ast_cli_unregister_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
01500 
01501    /* Allow any threads waiting for this lock to pass (avoids a race) */
01502    AST_RWLIST_UNLOCK(&queries);
01503    usleep(1);
01504    AST_RWLIST_WRLOCK(&queries);
01505 
01506    AST_RWLIST_UNLOCK(&queries);
01507    return 0;
01508 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ODBC lookups" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1560 of file func_odbc.c.

char* app_odbcfinish = "ODBCFinish" [static]

Definition at line 829 of file func_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1560 of file func_odbc.c.

struct ast_cli_entry cli_func_odbc[] [static]

Initial value:

 {
   { .handler =  cli_odbc_write , .summary =  "Test setting a func_odbc function" ,__VA_ARGS__ },
   { .handler =  cli_odbc_read , .summary =  "Test reading a func_odbc function" ,__VA_ARGS__ },
}

Definition at line 1434 of file func_odbc.c.

Referenced by load_module(), and unload_module().

struct ast_threadstorage coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , } [static]

Definition at line 145 of file func_odbc.c.

struct ast_threadstorage colnames_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_colnames_buf , .custom_init = NULL , } [static]

Definition at line 146 of file func_odbc.c.

Referenced by acf_odbc_read().

char* config = "func_odbc.conf" [static]

Definition at line 101 of file func_odbc.c.

struct ast_custom_function escape_function [static]

Initial value:

 {
   .name = "SQL_ESC",
   .read = acf_escape,
   .write = NULL,
}

Definition at line 784 of file func_odbc.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function fetch_function [static]

Initial value:

 {
   .name = "ODBC_FETCH",
   .read = acf_fetch,
   .write = NULL,
}

Definition at line 823 of file func_odbc.c.

Referenced by load_module(), and unload_module().

struct ast_datastore_info odbc_info [static]

Initial value:

 {
   .type = "FUNC_ODBC",
   .destroy = odbc_datastore_free,
}

Definition at line 122 of file func_odbc.c.

Referenced by acf_fetch(), and exec_odbcfinish().

int resultcount = 0 [static]

Definition at line 141 of file func_odbc.c.

struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , } [static]

Definition at line 144 of file func_odbc.c.

Referenced by acf_odbc_write().

struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , } [static]

Definition at line 143 of file func_odbc.c.

Referenced by acf_odbc_read(), acf_odbc_write(), config_pgsql(), destroy_pgsql(), realtime_multi_pgsql(), realtime_pgsql(), realtime_update2_handler(), store_pgsql(), update2_odbc(), update2_pgsql(), update2_prepare(), and update_pgsql().


Generated on Mon Mar 19 11:30:48 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7