Mon Oct 8 12:39:23 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 = "ac1f6a56484a8820659555499174e588" , .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 1568 of file func_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 1568 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 776 of file func_odbc.c.

00777 {
00778    char *out = buf;
00779 
00780    for (; *data && out - buf < len; data++) {
00781       if (*data == '\'') {
00782          *out = '\'';
00783          out++;
00784       }
00785       *out++ = *data;
00786    }
00787    *out = '\0';
00788 
00789    return 0;
00790 }

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

Definition at line 798 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().

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

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

Definition at line 416 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().

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

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

Definition at line 211 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().

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

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

Definition at line 1086 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.

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

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

Definition at line 1296 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.

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

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

Definition at line 839 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().

00840 {
00841    struct ast_datastore *store;
00842 
00843    ast_channel_lock(chan);
00844    store = ast_channel_datastore_find(chan, &odbc_info, data);
00845    if (store) {
00846       ast_channel_datastore_remove(chan, store);
00847       ast_datastore_free(store);
00848    }
00849    ast_channel_unlock(chan);
00850    return 0;
00851 }

static int free_acf_query ( struct acf_odbc_query query  )  [static]

Definition at line 1072 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().

01073 {
01074    if (query) {
01075       if (query->acf) {
01076          if (query->acf->name)
01077             ast_free((char *)query->acf->name);
01078          ast_string_field_free_memory(query->acf);
01079          ast_free(query->acf);
01080       }
01081       ast_free(query);
01082    }
01083    return 0;
01084 }

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

Definition at line 168 of file func_odbc.c.

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

Referenced by acf_odbc_read(), and acf_odbc_write().

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

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

Definition at line 853 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().

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

static int load_module ( void   )  [static]

Definition at line 1447 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_STATUS_FILEINVALID, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), and LOG_NOTICE.

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

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 
00155    if (!result) {
00156       return;
00157    }
00158 
00159    AST_LIST_LOCK(result);
00160    while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
00161       ast_free(row);
00162    }
00163    AST_LIST_UNLOCK(result);
00164    AST_LIST_HEAD_DESTROY(result);
00165    ast_free(result);
00166 }

static int reload ( void   )  [static]

Definition at line 1518 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_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, free_acf_query(), and init_acf_query().

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

static int unload_module ( void   )  [static]

Definition at line 1492 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.

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


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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1568 of file func_odbc.c.

char* app_odbcfinish = "ODBCFinish" [static]

Definition at line 837 of file func_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1568 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 1442 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 792 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 831 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 Oct 8 12:39:23 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7