Fri Nov 12 12:03:01 2010

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"
Include dependency graph for func_odbc.c:

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  { 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, void *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 = "0901e4e500243c855563a2d78b0c03e4" , .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
struct ast_datastore_info odbc_info
enum { ... }  odbc_option_flags
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

anonymous enum
Enumerator:
OPT_ESCAPECOMMAS 
OPT_MULTIROW 

Definition at line 102 of file func_odbc.c.

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


Function Documentation

static void __init_coldata_buf ( void   )  [static]

Definition at line 144 of file func_odbc.c.

00148 {

static void __init_colnames_buf ( void   )  [static]

Definition at line 145 of file func_odbc.c.

00148 {

static void __init_sql2_buf ( void   )  [static]

Definition at line 143 of file func_odbc.c.

00148 {

static void __init_sql_buf ( void   )  [static]

Definition at line 142 of file func_odbc.c.

00148 {

static void __reg_module ( void   )  [static]

Definition at line 1444 of file func_odbc.c.

static void __unreg_module ( void   )  [static]

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

00678 {
00679    char *out = buf;
00680 
00681    for (; *data && out - buf < len; data++) {
00682       if (*data == '\'') {
00683          *out = '\'';
00684          out++;
00685       }
00686       *out++ = *data;
00687    }
00688    *out = '\0';
00689 
00690    return 0;
00691 }

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

Definition at line 699 of file func_odbc.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), 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, acf_odbc_query::list, odbc_datastore::names, odbc_info, and pbx_builtin_setvar_helper().

00700 {
00701    struct ast_datastore *store;
00702    struct odbc_datastore *resultset;
00703    struct odbc_datastore_row *row;
00704    store = ast_channel_datastore_find(chan, &odbc_info, data);
00705    if (!store) {
00706       pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
00707       return -1;
00708    }
00709    resultset = store->data;
00710    AST_LIST_LOCK(resultset);
00711    row = AST_LIST_REMOVE_HEAD(resultset, list);
00712    AST_LIST_UNLOCK(resultset);
00713    if (!row) {
00714       /* Cleanup datastore */
00715       ast_channel_datastore_remove(chan, store);
00716       ast_datastore_free(store);
00717       pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
00718       return -1;
00719    }
00720    pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
00721    ast_copy_string(buf, row->data, len);
00722    ast_free(row);
00723    pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
00724    return 0;
00725 }

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

Definition at line 375 of file func_odbc.c.

References acf_odbc_query::acf, AST_APP_ARG, ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_alloc, ast_channel_datastore_add(), ast_channel_free(), ast_copy_string(), ast_datastore_alloc, ast_debug, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_ast_str_SQLGetData(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj(), ast_realloc, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_append_escapecommas(), ast_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_strlen(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strlen_zero(), ast_test_flag, ast_verb, coldata_buf, colnames_buf, ast_datastore::data, dsn, generic_execute(), acf_odbc_query::list, LOG_ERROR, LOG_WARNING, ast_custom_function::name, odbc_datastore_free(), odbc_info, OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), acf_odbc_query::readhandle, resultcount, acf_odbc_query::rowlimit, sql_buf, acf_odbc_query::sql_read, and status.

Referenced by init_acf_query().

00376 {
00377    struct odbc_obj *obj = NULL;
00378    struct acf_odbc_query *query;
00379    char varname[15], rowcount[12] = "-1";
00380    struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
00381    int res, x, y, buflen = 0, escapecommas, rowlimit = 1, dsn, bogus_chan = 0;
00382    AST_DECLARE_APP_ARGS(args,
00383       AST_APP_ARG(field)[100];
00384    );
00385    SQLHSTMT stmt = NULL;
00386    SQLSMALLINT colcount=0;
00387    SQLLEN indicator;
00388    SQLSMALLINT collength;
00389    struct odbc_datastore *resultset = NULL;
00390    struct odbc_datastore_row *row = NULL;
00391    struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
00392    const char *status = "FAILURE";
00393 
00394    if (!sql) {
00395       pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00396       return -1;
00397    }
00398 
00399    ast_str_reset(colnames);
00400 
00401    AST_RWLIST_RDLOCK(&queries);
00402    AST_RWLIST_TRAVERSE(&queries, query, list) {
00403       if (!strcmp(query->acf->name, cmd)) {
00404          break;
00405       }
00406    }
00407 
00408    if (!query) {
00409       ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
00410       AST_RWLIST_UNLOCK(&queries);
00411       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00412       pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00413       return -1;
00414    }
00415 
00416    if (!chan) {
00417       if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) {
00418          bogus_chan = 1;
00419       }
00420    }
00421 
00422    if (chan) {
00423       ast_autoservice_start(chan);
00424    }
00425 
00426    AST_STANDARD_APP_ARGS(args, s);
00427    for (x = 0; x < args.argc; x++) {
00428       snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00429       pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
00430    }
00431 
00432    ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
00433 
00434    /* Restore prior values */
00435    for (x = 0; x < args.argc; x++) {
00436       snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00437       pbx_builtin_setvar_helper(chan, varname, NULL);
00438    }
00439 
00440    /* Save these flags, so we can release the lock */
00441    escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
00442    if (ast_test_flag(query, OPT_MULTIROW)) {
00443       resultset = ast_calloc(1, sizeof(*resultset));
00444       AST_LIST_HEAD_INIT(resultset);
00445       if (query->rowlimit) {
00446          rowlimit = query->rowlimit;
00447       } else {
00448          rowlimit = INT_MAX;
00449       }
00450    }
00451    AST_RWLIST_UNLOCK(&queries);
00452 
00453    for (dsn = 0; dsn < 5; dsn++) {
00454       if (!ast_strlen_zero(query->readhandle[dsn])) {
00455          obj = ast_odbc_request_obj(query->readhandle[dsn], 0);
00456          if (obj) {
00457             stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql));
00458          }
00459       }
00460       if (stmt) {
00461          break;
00462       }
00463    }
00464 
00465    if (!stmt) {
00466       ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
00467       if (obj) {
00468          ast_odbc_release_obj(obj);
00469          obj = NULL;
00470       }
00471       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00472       if (chan) {
00473          ast_autoservice_stop(chan);
00474       }
00475       if (bogus_chan) {
00476          ast_channel_free(chan);
00477       }
00478       return -1;
00479    }
00480 
00481    res = SQLNumResultCols(stmt, &colcount);
00482    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00483       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
00484       SQLCloseCursor(stmt);
00485       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00486       ast_odbc_release_obj(obj);
00487       obj = NULL;
00488       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00489       if (chan) {
00490          ast_autoservice_stop(chan);
00491       }
00492       if (bogus_chan) {
00493          ast_channel_free(chan);
00494       }
00495       return -1;
00496    }
00497 
00498    res = SQLFetch(stmt);
00499    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00500       int res1 = -1;
00501       if (res == SQL_NO_DATA) {
00502          ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
00503          res1 = 0;
00504          buf[0] = '\0';
00505          ast_copy_string(rowcount, "0", sizeof(rowcount));
00506          status = "NODATA";
00507       } else {
00508          ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
00509          status = "FETCHERROR";
00510       }
00511       SQLCloseCursor(stmt);
00512       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00513       ast_odbc_release_obj(obj);
00514       obj = NULL;
00515       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00516       pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00517       if (chan)
00518          ast_autoservice_stop(chan);
00519       if (bogus_chan)
00520          ast_channel_free(chan);
00521       return res1;
00522    }
00523 
00524    status = "SUCCESS";
00525 
00526    for (y = 0; y < rowlimit; y++) {
00527       buf[0] = '\0';
00528       for (x = 0; x < colcount; x++) {
00529          int i;
00530          struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
00531          char *ptrcoldata;
00532 
00533          if (y == 0) {
00534             char colname[256];
00535             SQLULEN maxcol;
00536 
00537             res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
00538             ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x);
00539             if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
00540                snprintf(colname, sizeof(colname), "field%d", x);
00541             }
00542 
00543             ast_str_make_space(&coldata, maxcol + 1);
00544 
00545             if (ast_str_strlen(colnames)) {
00546                ast_str_append(&colnames, 0, ",");
00547             }
00548             ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
00549 
00550             if (resultset) {
00551                void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
00552                if (!tmp) {
00553                   ast_log(LOG_ERROR, "No space for a new resultset?\n");
00554                   ast_free(resultset);
00555                   SQLCloseCursor(stmt);
00556                   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00557                   ast_odbc_release_obj(obj);
00558                   obj = NULL;
00559                   pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00560                   pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00561                   if (chan)
00562                      ast_autoservice_stop(chan);
00563                   if (bogus_chan)
00564                      ast_channel_free(chan);
00565                   return -1;
00566                }
00567                resultset = tmp;
00568                strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
00569             }
00570          }
00571 
00572          buflen = strlen(buf);
00573          res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
00574          if (indicator == SQL_NULL_DATA) {
00575             ast_debug(3, "Got NULL data\n");
00576             ast_str_reset(coldata);
00577             res = SQL_SUCCESS;
00578          }
00579 
00580          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00581             ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
00582             y = -1;
00583             buf[0] = '\0';
00584             goto end_acf_read;
00585          }
00586 
00587          ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
00588 
00589          if (x) {
00590             buf[buflen++] = ',';
00591          }
00592 
00593          /* Copy data, encoding '\' and ',' for the argument parser */
00594          ptrcoldata = ast_str_buffer(coldata);
00595          for (i = 0; i < ast_str_strlen(coldata); i++) {
00596             if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
00597                buf[buflen++] = '\\';
00598             }
00599             buf[buflen++] = ptrcoldata[i];
00600 
00601             if (buflen >= len - 2) {
00602                break;
00603             }
00604 
00605             if (ptrcoldata[i] == '\0') {
00606                break;
00607             }
00608          }
00609 
00610          buf[buflen] = '\0';
00611          ast_debug(2, "buf is now set to '%s'\n", buf);
00612       }
00613       ast_debug(2, "buf is now set to '%s'\n", buf);
00614 
00615       if (resultset) {
00616          row = ast_calloc(1, sizeof(*row) + buflen + 1);
00617          if (!row) {
00618             ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
00619             status = "MEMERROR";
00620             goto end_acf_read;
00621          }
00622          strcpy((char *)row + sizeof(*row), buf);
00623          AST_LIST_INSERT_TAIL(resultset, row, list);
00624 
00625          /* Get next row */
00626          res = SQLFetch(stmt);
00627          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00628             if (res != SQL_NO_DATA) {
00629                ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
00630             }
00631             /* Number of rows in the resultset */
00632             y++;
00633             break;
00634          }
00635       }
00636    }
00637 
00638 end_acf_read:
00639    snprintf(rowcount, sizeof(rowcount), "%d", y);
00640    pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00641    pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
00642    pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
00643    if (resultset) {
00644       int uid;
00645       struct ast_datastore *odbc_store;
00646       uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
00647       snprintf(buf, len, "%d", uid);
00648       odbc_store = ast_datastore_alloc(&odbc_info, buf);
00649       if (!odbc_store) {
00650          ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel.  Results fail.\n");
00651          pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
00652          odbc_datastore_free(resultset);
00653          SQLCloseCursor(stmt);
00654          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00655          ast_odbc_release_obj(obj);
00656          obj = NULL;
00657          if (chan)
00658             ast_autoservice_stop(chan);
00659          if (bogus_chan)
00660             ast_channel_free(chan);
00661          return -1;
00662       }
00663       odbc_store->data = resultset;
00664       ast_channel_datastore_add(chan, odbc_store);
00665    }
00666    SQLCloseCursor(stmt);
00667    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00668    ast_odbc_release_obj(obj);
00669    obj = NULL;
00670    if (chan)
00671       ast_autoservice_stop(chan);
00672    if (bogus_chan)
00673       ast_channel_free(chan);
00674    return 0;
00675 }

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

Note:
Okay, this part is confusing. Transactions belong to a single database handle. Therefore, when working with transactions, we CANNOT failover to multiple DSNs. We MUST have a single handle all the way through the transaction, or else we CANNOT enforce atomicity.

Definition at line 203 of file func_odbc.c.

References acf_odbc_query::acf, AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_alloc, ast_channel_free(), AST_DECLARE_APP_ARGS, 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_strlen(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strlen_zero(), buf, 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().

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

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

Definition at line 978 of file func_odbc.c.

References acf_odbc_query::acf, ast_cli_args::argc, ast_cli_args::argv, AST_APP_ARG, ast_channel_alloc, ast_channel_free(), ast_cli(), ast_debug, AST_DECLARE_APP_ARGS, ast_odbc_ast_str_SQLGetData(), 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_make_space(), ast_str_set(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strdup, ast_strlen_zero(), chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, coldata_buf, ast_cli_entry::command, dsn, ast_cli_args::fd, generic_execute(), acf_odbc_query::list, ast_cli_args::n, ast_custom_function::name, pbx_builtin_pushvar_helper(), ast_cli_args::pos, acf_odbc_query::readhandle, sql_buf, acf_odbc_query::sql_read, ast_cli_entry::usage, and ast_cli_args::word.

00979 {
00980    AST_DECLARE_APP_ARGS(args,
00981       AST_APP_ARG(field)[100];
00982    );
00983    struct ast_str *sql;
00984    char *char_args, varname[10];
00985    struct acf_odbc_query *query;
00986    struct ast_channel *chan;
00987    int i;
00988 
00989    switch (cmd) {
00990    case CLI_INIT:
00991       e->command = "odbc read";
00992       e->usage =
00993          "Usage: odbc read <name> <args> [exec]\n"
00994          "       Evaluates the SQL provided in the ODBC function <name>, and\n"
00995          "       optionally executes the function.  This function is intended for\n"
00996          "       testing purposes.  Remember to quote arguments containing spaces.\n";
00997       return NULL;
00998    case CLI_GENERATE:
00999       if (a->pos == 2) {
01000          int wordlen = strlen(a->word), which = 0;
01001          /* Complete function name */
01002          AST_RWLIST_RDLOCK(&queries);
01003          AST_RWLIST_TRAVERSE(&queries, query, list) {
01004             if (!strncasecmp(query->acf->name, a->word, wordlen)) {
01005                if (++which > a->n) {
01006                   char *res = ast_strdup(query->acf->name);
01007                   AST_RWLIST_UNLOCK(&queries);
01008                   return res;
01009                }
01010             }
01011          }
01012          AST_RWLIST_UNLOCK(&queries);
01013          return NULL;
01014       } else if (a->pos == 4) {
01015          return a->n == 0 ? ast_strdup("exec") : NULL;
01016       } else {
01017          return NULL;
01018       }
01019    }
01020 
01021    if (a->argc < 4 || a->argc > 5) {
01022       return CLI_SHOWUSAGE;
01023    }
01024 
01025    sql = ast_str_thread_get(&sql_buf, 16);
01026    if (!sql) {
01027       return CLI_FAILURE;
01028    }
01029 
01030    AST_RWLIST_RDLOCK(&queries);
01031    AST_RWLIST_TRAVERSE(&queries, query, list) {
01032       if (!strcmp(query->acf->name, a->argv[2])) {
01033          break;
01034       }
01035    }
01036 
01037    if (!query) {
01038       ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
01039       AST_RWLIST_UNLOCK(&queries);
01040       return CLI_SHOWUSAGE;
01041    }
01042 
01043    if (ast_strlen_zero(query->sql_read)) {
01044       ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
01045       AST_RWLIST_UNLOCK(&queries);
01046       return CLI_SUCCESS;
01047    }
01048 
01049    ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
01050 
01051    /* Evaluate function */
01052    char_args = ast_strdupa(a->argv[3]);
01053 
01054    chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc");
01055 
01056    AST_STANDARD_APP_ARGS(args, char_args);
01057    for (i = 0; i < args.argc; i++) {
01058       snprintf(varname, sizeof(varname), "ARG%d", i + 1);
01059       pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
01060    }
01061 
01062    ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
01063    ast_channel_free(chan);
01064 
01065    if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
01066       /* Execute the query */
01067       struct odbc_obj *obj = NULL;
01068       int dsn, executed = 0;
01069       SQLHSTMT stmt;
01070       int rows = 0, res, x;
01071       SQLSMALLINT colcount = 0, collength;
01072       SQLLEN indicator;
01073       struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
01074       char colname[256];
01075       SQLULEN maxcol;
01076 
01077       for (dsn = 0; dsn < 5; dsn++) {
01078          if (ast_strlen_zero(query->readhandle[dsn])) {
01079             continue;
01080          }
01081          ast_debug(1, "Found handle %s\n", query->readhandle[dsn]);
01082          if (!(obj = ast_odbc_request_obj(query->readhandle[dsn], 0))) {
01083             continue;
01084          }
01085 
01086          ast_debug(1, "Got obj\n");
01087          if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
01088             ast_odbc_release_obj(obj);
01089             obj = NULL;
01090             continue;
01091          }
01092 
01093          executed = 1;
01094 
01095          res = SQLNumResultCols(stmt, &colcount);
01096          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01097             ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
01098             SQLCloseCursor(stmt);
01099             SQLFreeHandle (SQL_HANDLE_STMT, stmt);
01100             ast_odbc_release_obj(obj);
01101             obj = NULL;
01102             AST_RWLIST_UNLOCK(&queries);
01103             return CLI_SUCCESS;
01104          }
01105 
01106          res = SQLFetch(stmt);
01107          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01108             SQLCloseCursor(stmt);
01109             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01110             ast_odbc_release_obj(obj);
01111             obj = NULL;
01112             if (res == SQL_NO_DATA) {
01113                ast_cli(a->fd, "Returned %d rows.  Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql));
01114                break;
01115             } else {
01116                ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
01117             }
01118             AST_RWLIST_UNLOCK(&queries);
01119             return CLI_SUCCESS;
01120          }
01121          for (;;) {
01122             for (x = 0; x < colcount; x++) {
01123                res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
01124                if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
01125                   snprintf(colname, sizeof(colname), "field%d", x);
01126                }
01127 
01128                res = ast_odbc_ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator);
01129                if (indicator == SQL_NULL_DATA) {
01130                   ast_str_set(&coldata, 0, "(nil)");
01131                   res = SQL_SUCCESS;
01132                }
01133 
01134                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01135                   ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
01136                   SQLCloseCursor(stmt);
01137                   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01138                   ast_odbc_release_obj(obj);
01139                   obj = NULL;
01140                   AST_RWLIST_UNLOCK(&queries);
01141                   return CLI_SUCCESS;
01142                }
01143 
01144                ast_cli(a->fd, "%-20.20s  %s\n", colname, ast_str_buffer(coldata));
01145             }
01146             rows++;
01147 
01148             /* Get next row */
01149             res = SQLFetch(stmt);
01150             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01151                break;
01152             }
01153             ast_cli(a->fd, "%-20.20s  %s\n", "----------", "----------");
01154          }
01155          SQLCloseCursor(stmt);
01156          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01157          ast_odbc_release_obj(obj);
01158          obj = NULL;
01159          ast_cli(a->fd, "Returned %d row%s.  Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn, query->readhandle[dsn]);
01160          break;
01161       }
01162       if (obj) {
01163          ast_odbc_release_obj(obj);
01164          obj = NULL;
01165       }
01166 
01167       if (!executed) {
01168          ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
01169       }
01170    } else { /* No execution, just print out the resulting SQL */
01171       ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
01172    }
01173    AST_RWLIST_UNLOCK(&queries);
01174    return CLI_SUCCESS;
01175 }

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

Definition at line 1177 of file func_odbc.c.

References acf_odbc_query::acf, ast_cli_args::argc, ast_cli_args::argv, AST_APP_ARG, ast_channel_alloc, ast_channel_free(), ast_cli(), ast_debug, AST_DECLARE_APP_ARGS, 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_make_space(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strdup, ast_strlen_zero(), chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dsn, ast_cli_args::fd, generic_execute(), acf_odbc_query::list, ast_cli_args::n, ast_custom_function::name, pbx_builtin_pushvar_helper(), ast_cli_args::pos, S_OR, sql_buf, acf_odbc_query::sql_write, ast_cli_entry::usage, ast_cli_args::word, and acf_odbc_query::writehandle.

01178 {
01179    AST_DECLARE_APP_ARGS(values,
01180       AST_APP_ARG(field)[100];
01181    );
01182    AST_DECLARE_APP_ARGS(args,
01183       AST_APP_ARG(field)[100];
01184    );
01185    struct ast_str *sql;
01186    char *char_args, *char_values, varname[10];
01187    struct acf_odbc_query *query;
01188    struct ast_channel *chan;
01189    int i;
01190 
01191    switch (cmd) {
01192    case CLI_INIT:
01193       e->command = "odbc write";
01194       e->usage =
01195          "Usage: odbc write <name> <args> <value> [exec]\n"
01196          "       Evaluates the SQL provided in the ODBC function <name>, and\n"
01197          "       optionally executes the function.  This function is intended for\n"
01198          "       testing purposes.  Remember to quote arguments containing spaces.\n";
01199       return NULL;
01200    case CLI_GENERATE:
01201       if (a->pos == 2) {
01202          int wordlen = strlen(a->word), which = 0;
01203          /* Complete function name */
01204          AST_RWLIST_RDLOCK(&queries);
01205          AST_RWLIST_TRAVERSE(&queries, query, list) {
01206             if (!strncasecmp(query->acf->name, a->word, wordlen)) {
01207                if (++which > a->n) {
01208                   char *res = ast_strdup(query->acf->name);
01209                   AST_RWLIST_UNLOCK(&queries);
01210                   return res;
01211                }
01212             }
01213          }
01214          AST_RWLIST_UNLOCK(&queries);
01215          return NULL;
01216       } else if (a->pos == 5) {
01217          return a->n == 0 ? ast_strdup("exec") : NULL;
01218       } else {
01219          return NULL;
01220       }
01221    }
01222 
01223    if (a->argc < 5 || a->argc > 6) {
01224       return CLI_SHOWUSAGE;
01225    }
01226 
01227    sql = ast_str_thread_get(&sql_buf, 16);
01228    if (!sql) {
01229       return CLI_FAILURE;
01230    }
01231 
01232    AST_RWLIST_RDLOCK(&queries);
01233    AST_RWLIST_TRAVERSE(&queries, query, list) {
01234       if (!strcmp(query->acf->name, a->argv[2])) {
01235          break;
01236       }
01237    }
01238 
01239    if (!query) {
01240       ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
01241       AST_RWLIST_UNLOCK(&queries);
01242       return CLI_SHOWUSAGE;
01243    }
01244 
01245    if (ast_strlen_zero(query->sql_write)) {
01246       ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
01247       AST_RWLIST_UNLOCK(&queries);
01248       return CLI_SUCCESS;
01249    }
01250 
01251    ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
01252 
01253    /* Evaluate function */
01254    char_args = ast_strdupa(a->argv[3]);
01255    char_values = ast_strdupa(a->argv[4]);
01256 
01257    chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc");
01258 
01259    AST_STANDARD_APP_ARGS(args, char_args);
01260    for (i = 0; i < args.argc; i++) {
01261       snprintf(varname, sizeof(varname), "ARG%d", i + 1);
01262       pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
01263    }
01264 
01265    /* Parse values, just like arguments */
01266    AST_STANDARD_APP_ARGS(values, char_values);
01267    for (i = 0; i < values.argc; i++) {
01268       snprintf(varname, sizeof(varname), "VAL%d", i + 1);
01269       pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
01270    }
01271 
01272    /* Additionally set the value as a whole (but push an empty string if value is NULL) */
01273    pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
01274    ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
01275    ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
01276    ast_channel_free(chan);
01277 
01278    if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
01279       /* Execute the query */
01280       struct odbc_obj *obj = NULL;
01281       int dsn, executed = 0;
01282       SQLHSTMT stmt;
01283       SQLLEN rows = -1;
01284 
01285       for (dsn = 0; dsn < 5; dsn++) {
01286          if (ast_strlen_zero(query->writehandle[dsn])) {
01287             continue;
01288          }
01289          if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) {
01290             continue;
01291          }
01292          if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
01293             ast_odbc_release_obj(obj);
01294             obj = NULL;
01295             continue;
01296          }
01297 
01298          SQLRowCount(stmt, &rows);
01299          SQLCloseCursor(stmt);
01300          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01301          ast_odbc_release_obj(obj);
01302          obj = NULL;
01303          ast_cli(a->fd, "Affected %d rows.  Query executed on handle %d [%s]\n", (int)rows, dsn, query->writehandle[dsn]);
01304          executed = 1;
01305          break;
01306       }
01307 
01308       if (!executed) {
01309          ast_cli(a->fd, "Failed to execute query.\n");
01310       }
01311    } else { /* No execution, just print out the resulting SQL */
01312       ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
01313    }
01314    AST_RWLIST_UNLOCK(&queries);
01315    return CLI_SUCCESS;
01316 }

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

Definition at line 735 of file func_odbc.c.

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

Referenced by load_module().

00736 {
00737    struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data);
00738    if (!store) /* Already freed; no big deal. */
00739       return 0;
00740    ast_channel_datastore_remove(chan, store);
00741    ast_datastore_free(store);
00742    return 0;
00743 }

static int free_acf_query ( struct acf_odbc_query query  )  [static]

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

00965 {
00966    if (query) {
00967       if (query->acf) {
00968          if (query->acf->name)
00969             ast_free((char *)query->acf->name);
00970          ast_string_field_free_memory(query->acf);
00971          ast_free(query->acf);
00972       }
00973       ast_free(query);
00974    }
00975    return 0;
00976 }

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

Definition at line 160 of file func_odbc.c.

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

Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), and cli_odbc_write().

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

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

Definition at line 745 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_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, LOG_ERROR, LOG_WARNING, OPT_ESCAPECOMMAS, OPT_MULTIROW, ast_custom_function::read, and synopsis.

Referenced by load_module(), and reload().

00746 {
00747    const char *tmp;
00748    int i;
00749 
00750    if (!cfg || !catg) {
00751       return EINVAL;
00752    }
00753 
00754    *query = ast_calloc(1, sizeof(struct acf_odbc_query));
00755    if (! (*query))
00756       return ENOMEM;
00757 
00758    if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
00759       char *tmp2 = ast_strdupa(tmp);
00760       AST_DECLARE_APP_ARGS(writeconf,
00761          AST_APP_ARG(dsn)[5];
00762       );
00763       AST_STANDARD_APP_ARGS(writeconf, tmp2);
00764       for (i = 0; i < 5; i++) {
00765          if (!ast_strlen_zero(writeconf.dsn[i]))
00766             ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
00767       }
00768    }
00769 
00770    if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
00771       char *tmp2 = ast_strdupa(tmp);
00772       AST_DECLARE_APP_ARGS(readconf,
00773          AST_APP_ARG(dsn)[5];
00774       );
00775       AST_STANDARD_APP_ARGS(readconf, tmp2);
00776       for (i = 0; i < 5; i++) {
00777          if (!ast_strlen_zero(readconf.dsn[i]))
00778             ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
00779       }
00780    } else {
00781       /* If no separate readhandle, then use the writehandle for reading */
00782       for (i = 0; i < 5; i++) {
00783          if (!ast_strlen_zero((*query)->writehandle[i]))
00784             ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
00785       }
00786    }
00787 
00788    if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")))
00789       ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00790    else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) {
00791       ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s.  Please use 'readsql' instead.\n", catg);
00792       ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00793    }
00794 
00795    if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) {
00796       ast_free(*query);
00797       *query = NULL;
00798       ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
00799       return EINVAL;
00800    }
00801 
00802    if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")))
00803       ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00804    else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) {
00805       ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s.  Please use 'writesql' instead.\n", catg);
00806       ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00807    }
00808 
00809    if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) {
00810       ast_free(*query);
00811       *query = NULL;
00812       ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
00813       return EINVAL;
00814    }
00815 
00816    if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
00817       ast_copy_string((*query)->sql_insert, tmp, sizeof((*query)->sql_insert));
00818    }
00819 
00820    /* Allow escaping of embedded commas in fields to be turned off */
00821    ast_set_flag((*query), OPT_ESCAPECOMMAS);
00822    if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
00823       if (ast_false(tmp))
00824          ast_clear_flag((*query), OPT_ESCAPECOMMAS);
00825    }
00826 
00827    if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
00828       if (strcasecmp(tmp, "multirow") == 0)
00829          ast_set_flag((*query), OPT_MULTIROW);
00830       if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
00831          sscanf(tmp, "%30d", &((*query)->rowlimit));
00832    }
00833 
00834    (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
00835    if (! (*query)->acf) {
00836       ast_free(*query);
00837       *query = NULL;
00838       return ENOMEM;
00839    }
00840    if (ast_string_field_init((*query)->acf, 128)) {
00841       ast_free((*query)->acf);
00842       ast_free(*query);
00843       *query = NULL;
00844       return ENOMEM;
00845    }
00846 
00847    if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
00848       if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
00849          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00850       }
00851    } else {
00852       if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
00853          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00854       }
00855    }
00856 
00857    if (!((*query)->acf->name)) {
00858       ast_string_field_free_memory((*query)->acf);
00859       ast_free((*query)->acf);
00860       ast_free(*query);
00861       *query = NULL;
00862       return ENOMEM;
00863    }
00864 
00865    if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
00866       ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
00867    } else {
00868       ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
00869    }
00870 
00871    if (ast_strlen_zero((*query)->acf->syntax)) {
00872       ast_free((char *)(*query)->acf->name);
00873       ast_string_field_free_memory((*query)->acf);
00874       ast_free((*query)->acf);
00875       ast_free(*query);
00876       *query = NULL;
00877       return ENOMEM;
00878    }
00879 
00880    if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
00881       ast_string_field_set((*query)->acf, synopsis, tmp);
00882    } else {
00883       ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
00884    }
00885 
00886    if (ast_strlen_zero((*query)->acf->synopsis)) {
00887       ast_free((char *)(*query)->acf->name);
00888       ast_string_field_free_memory((*query)->acf);
00889       ast_free((*query)->acf);
00890       ast_free(*query);
00891       *query = NULL;
00892       return ENOMEM;
00893    }
00894 
00895    if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) {
00896       ast_string_field_build((*query)->acf, desc,
00897                "Runs the following query, as defined in func_odbc.conf, performing\n"
00898                   "substitution of the arguments into the query as specified by ${ARG1},\n"
00899                "${ARG2}, ... ${ARGn}.  When setting the function, the values are provided\n"
00900                "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
00901                "%s"
00902                "\nRead:\n%s\n\nWrite:\n%s\n%s%s%s",
00903                ast_strlen_zero((*query)->sql_insert) ? "" :
00904                   "If the write query affects no rows, the insert query will be\n"
00905                   "performed.\n",
00906                (*query)->sql_read,
00907                (*query)->sql_write,
00908                ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n",
00909                ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
00910                ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
00911    } else if (!ast_strlen_zero((*query)->sql_read)) {
00912       ast_string_field_build((*query)->acf, desc,
00913                   "Runs the following query, as defined in func_odbc.conf, performing\n"
00914                      "substitution of the arguments into the query as specified by ${ARG1},\n"
00915                   "${ARG2}, ... ${ARGn}.  This function may only be read, not set.\n\nSQL:\n%s\n",
00916                   (*query)->sql_read);
00917    } else if (!ast_strlen_zero((*query)->sql_write)) {
00918       ast_string_field_build((*query)->acf, desc,  
00919                "Runs the following query, as defined in func_odbc.conf, performing\n"
00920                   "substitution of the arguments into the query as specified by ${ARG1},\n"
00921                "${ARG2}, ... ${ARGn}.  The values are provided either in whole as\n"
00922                "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
00923                "This function may only be set.\n%sSQL:\n%s\n%s%s%s",
00924                ast_strlen_zero((*query)->sql_insert) ? "" :
00925                   "If the write query affects no rows, the insert query will be\n"
00926                   "performed.\n",
00927                (*query)->sql_write,
00928                ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n",
00929                ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert,
00930                ast_strlen_zero((*query)->sql_insert) ? "" : "\n");
00931    } else {
00932       ast_string_field_free_memory((*query)->acf);
00933       ast_free((char *)(*query)->acf->name);
00934       ast_free((*query)->acf);
00935       ast_free(*query);
00936       ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute.  Ignoring.\n", catg);
00937       return EINVAL;
00938    }
00939 
00940    if (ast_strlen_zero((*query)->acf->desc)) {
00941       ast_string_field_free_memory((*query)->acf);
00942       ast_free((char *)(*query)->acf->name);
00943       ast_free((*query)->acf);
00944       ast_free(*query);
00945       *query = NULL;
00946       return ENOMEM;
00947    }
00948 
00949    if (ast_strlen_zero((*query)->sql_read)) {
00950       (*query)->acf->read = NULL;
00951    } else {
00952       (*query)->acf->read = acf_odbc_read;
00953    }
00954 
00955    if (ast_strlen_zero((*query)->sql_write)) {
00956       (*query)->acf->write = NULL;
00957    } else {
00958       (*query)->acf->write = acf_odbc_write;
00959    }
00960 
00961    return 0;
00962 }

static int load_module ( void   )  [static]

Definition at line 1323 of file func_odbc.c.

References acf_odbc_query::acf, app_odbcfinish, 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(), acf_odbc_query::list, LOG_ERROR, and LOG_NOTICE.

01324 {
01325    int res = 0;
01326    struct ast_config *cfg;
01327    char *catg;
01328    struct ast_flags config_flags = { 0 };
01329 
01330    res |= ast_custom_function_register(&fetch_function);
01331    res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish);
01332    AST_RWLIST_WRLOCK(&queries);
01333 
01334    cfg = ast_config_load(config, config_flags);
01335    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
01336       ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
01337       AST_RWLIST_UNLOCK(&queries);
01338       return AST_MODULE_LOAD_DECLINE;
01339    }
01340 
01341    for (catg = ast_category_browse(cfg, NULL);
01342         catg;
01343         catg = ast_category_browse(cfg, catg)) {
01344       struct acf_odbc_query *query = NULL;
01345       int err;
01346 
01347       if ((err = init_acf_query(cfg, catg, &query))) {
01348          if (err == ENOMEM)
01349             ast_log(LOG_ERROR, "Out of memory\n");
01350          else if (err == EINVAL)
01351             ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
01352          else
01353             ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
01354       } else {
01355          AST_RWLIST_INSERT_HEAD(&queries, query, list);
01356          ast_custom_function_register(query->acf);
01357       }
01358    }
01359 
01360    ast_config_destroy(cfg);
01361    res |= ast_custom_function_register(&escape_function);
01362    ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
01363 
01364    AST_RWLIST_UNLOCK(&queries);
01365    return res;
01366 }

static void odbc_datastore_free ( void *  data  )  [static]

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

Referenced by acf_odbc_read().

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

static int reload ( void   )  [static]

Definition at line 1394 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(), init_acf_query(), acf_odbc_query::list, LOG_ERROR, and LOG_WARNING.

01395 {
01396    int res = 0;
01397    struct ast_config *cfg;
01398    struct acf_odbc_query *oldquery;
01399    char *catg;
01400    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
01401 
01402    cfg = ast_config_load(config, config_flags);
01403    if (cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
01404       return 0;
01405 
01406    AST_RWLIST_WRLOCK(&queries);
01407 
01408    while (!AST_RWLIST_EMPTY(&queries)) {
01409       oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
01410       ast_custom_function_unregister(oldquery->acf);
01411       free_acf_query(oldquery);
01412    }
01413 
01414    if (!cfg) {
01415       ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
01416       goto reload_out;
01417    }
01418 
01419    for (catg = ast_category_browse(cfg, NULL);
01420         catg;
01421         catg = ast_category_browse(cfg, catg)) {
01422       struct acf_odbc_query *query = NULL;
01423 
01424       if (init_acf_query(cfg, catg, &query)) {
01425          ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
01426       } else {
01427          AST_RWLIST_INSERT_HEAD(&queries, query, list);
01428          ast_custom_function_register(query->acf);
01429       }
01430    }
01431 
01432    ast_config_destroy(cfg);
01433 reload_out:
01434    AST_RWLIST_UNLOCK(&queries);
01435    return res;
01436 }

static int unload_module ( void   )  [static]

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

Definition at line 1444 of file func_odbc.c.

char* app_odbcfinish = "ODBCFinish" [static]

Definition at line 733 of file func_odbc.c.

Referenced by load_module(), and unload_module().

Definition at line 1444 of file func_odbc.c.

struct ast_cli_entry cli_func_odbc[] [static]
Initial value:
 {
   AST_CLI_DEFINE(cli_odbc_write, "Test setting a func_odbc function"),
   AST_CLI_DEFINE(cli_odbc_read, "Test reading a func_odbc function"),
}

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

Referenced by acf_odbc_read(), and cli_odbc_read().

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

Definition at line 145 of file func_odbc.c.

Referenced by acf_odbc_read().

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

Definition at line 100 of file func_odbc.c.

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

Definition at line 693 of file func_odbc.c.

Referenced by load_module(), and unload_module().

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

Definition at line 727 of file func_odbc.c.

Referenced by load_module(), and unload_module().

Initial value:
 {
   .type = "FUNC_ODBC",
   .destroy = odbc_datastore_free,
}

Definition at line 121 of file func_odbc.c.

Referenced by acf_fetch(), acf_odbc_read(), and exec_odbcfinish().

enum { ... } odbc_option_flags
int resultcount = 0 [static]

Definition at line 140 of file func_odbc.c.

Referenced by acf_odbc_read().

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

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

Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), and cli_odbc_write().


Generated by  doxygen 1.6.2