Fri Jun 19 12:10:37 2009

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"

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 __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 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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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_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 char * desc_odbcfinish
static struct ast_custom_function escape_function
static struct ast_custom_function fetch_function
ast_datastore_info odbc_info
enum { ... }  odbc_option_flags
static int resultcount = 0
static char * syn_odbcfinish = "Clear the resultset of a successful multirow query"


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 49 of file func_odbc.c.

00049      {
00050    OPT_ESCAPECOMMAS =   (1 << 0),
00051    OPT_MULTIROW     =   (1 << 1),
00052 } odbc_option_flags;


Function Documentation

static void __init_coldata_buf ( void   )  [static]

Definition at line 88 of file func_odbc.c.

00092 {

static void __init_colnames_buf ( void   )  [static]

Definition at line 89 of file func_odbc.c.

00092 {

static void __reg_module ( void   )  [static]

Definition at line 954 of file func_odbc.c.

static void __unreg_module ( void   )  [static]

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

00549 {
00550    char *out = buf;
00551 
00552    for (; *data && out - buf < len; data++) {
00553       if (*data == '\'') {
00554          *out = '\'';
00555          out++;
00556       }
00557       *out++ = *data;
00558    }
00559    *out = '\0';
00560 
00561    return 0;
00562 }

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

Definition at line 576 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, chan, odbc_datastore_row::data, ast_datastore::data, odbc_datastore_row::list, odbc_datastore::names, odbc_info, and pbx_builtin_setvar_helper().

00577 {
00578    struct ast_datastore *store;
00579    struct odbc_datastore *resultset;
00580    struct odbc_datastore_row *row;
00581    store = ast_channel_datastore_find(chan, &odbc_info, data);
00582    if (!store) {
00583       return -1;
00584    }
00585    resultset = store->data;
00586    AST_LIST_LOCK(resultset);
00587    row = AST_LIST_REMOVE_HEAD(resultset, list);
00588    AST_LIST_UNLOCK(resultset);
00589    if (!row) {
00590       /* Cleanup datastore */
00591       ast_channel_datastore_remove(chan, store);
00592       ast_datastore_free(store);
00593       return -1;
00594    }
00595    pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
00596    ast_copy_string(buf, row->data, len);
00597    ast_free(row);
00598    return 0;
00599 }

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

Definition at line 258 of file func_odbc.c.

References acf_odbc_query::acf, AST_APP_ARG, ast_autoservice_start(), ast_calloc, ast_channel_alloc(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD_INIT, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_create(), ast_str_make_space(), ast_str_reset(), ast_str_thread_get(), ast_strlen_zero(), ast_test_flag, chan, colnames_buf, dsn, generic_execute(), ast_str::len, acf_odbc_query::list, LOG_ERROR, ast_custom_function::name, OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), acf_odbc_query::readhandle, acf_odbc_query::rowlimit, acf_odbc_query::sql_read, and ast_str::str.

Referenced by init_acf_query().

00259 {
00260    struct odbc_obj *obj = NULL;
00261    struct acf_odbc_query *query;
00262    char varname[15], rowcount[12] = "-1";
00263    struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
00264    int res, x, y, buflen = 0, escapecommas, rowlimit = 1, dsn, bogus_chan = 0;
00265    AST_DECLARE_APP_ARGS(args,
00266       AST_APP_ARG(field)[100];
00267    );
00268    SQLHSTMT stmt = NULL;
00269    SQLSMALLINT colcount=0;
00270    SQLLEN indicator;
00271    SQLSMALLINT collength;
00272    struct odbc_datastore *resultset = NULL;
00273    struct odbc_datastore_row *row = NULL;
00274    struct ast_str *sql = ast_str_create(16);
00275 
00276    if (!sql) {
00277       return -1;
00278    }
00279 
00280    ast_str_reset(colnames);
00281 
00282    AST_RWLIST_RDLOCK(&queries);
00283    AST_RWLIST_TRAVERSE(&queries, query, list) {
00284       if (!strcmp(query->acf->name, cmd)) {
00285          break;
00286       }
00287    }
00288 
00289    if (!query) {
00290       ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
00291       AST_RWLIST_UNLOCK(&queries);
00292       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00293       ast_free(sql);
00294       return -1;
00295    }
00296 
00297    if (!chan) {
00298       if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc")))
00299          bogus_chan = 1;
00300    }
00301 
00302    if (chan)
00303       ast_autoservice_start(chan);
00304 
00305    AST_STANDARD_APP_ARGS(args, s);
00306    for (x = 0; x < args.argc; x++) {
00307       snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00308       pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
00309    }
00310 
00311    ast_str_make_space(&sql, strlen(query->sql_read) * 2);
00312    pbx_substitute_variables_helper(chan, query->sql_read, sql->str, sql->len - 1);
00313 
00314    /* Restore prior values */
00315    for (x = 0; x < args.argc; x++) {
00316       snprintf(varname, sizeof(varname), "ARG%d", x + 1);
00317       pbx_builtin_setvar_helper(chan, varname, NULL);
00318    }
00319 
00320    /* Save these flags, so we can release the lock */
00321    escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
00322    if (ast_test_flag(query, OPT_MULTIROW)) {
00323       resultset = ast_calloc(1, sizeof(*resultset));
00324       AST_LIST_HEAD_INIT(resultset);
00325       if (query->rowlimit)
00326          rowlimit = query->rowlimit;
00327       else
00328          rowlimit = INT_MAX;
00329    }
00330    AST_RWLIST_UNLOCK(&queries);
00331 
00332    for (dsn = 0; dsn < 5; dsn++) {
00333       if (!ast_strlen_zero(query->readhandle[dsn])) {
00334          obj = ast_odbc_request_obj(query->readhandle[dsn], 0);
00335          if (obj)
00336             stmt = ast_odbc_direct_execute(obj, generic_execute, sql->str);
00337       }
00338       if (stmt)
00339          break;
00340    }
00341 
00342    if (!stmt) {
00343       ast_log(LOG_ERROR, "Unable to execute query [%s]\n", sql->str);
00344       if (obj)
00345          ast_odbc_release_obj(obj);
00346       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00347       if (chan)
00348          ast_autoservice_stop(chan);
00349       if (bogus_chan)
00350          ast_channel_free(chan);
00351       ast_free(sql);
00352       return -1;
00353    }
00354 
00355    res = SQLNumResultCols(stmt, &colcount);
00356    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00357       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql->str);
00358       SQLCloseCursor(stmt);
00359       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00360       ast_odbc_release_obj(obj);
00361       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00362       if (chan)
00363          ast_autoservice_stop(chan);
00364       if (bogus_chan)
00365          ast_channel_free(chan);
00366       ast_free(sql);
00367       return -1;
00368    }
00369 
00370    res = SQLFetch(stmt);
00371    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00372       int res1 = -1;
00373       if (res == SQL_NO_DATA) {
00374          ast_verb(4, "Found no rows [%s]\n", sql->str);
00375          res1 = 0;
00376          buf[0] = '\0';
00377          ast_copy_string(rowcount, "0", sizeof(rowcount));
00378       } else {
00379          ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str);
00380       }
00381       SQLCloseCursor(stmt);
00382       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00383       ast_odbc_release_obj(obj);
00384       pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00385       if (chan)
00386          ast_autoservice_stop(chan);
00387       if (bogus_chan)
00388          ast_channel_free(chan);
00389       ast_free(sql);
00390       return res1;
00391    }
00392 
00393    for (y = 0; y < rowlimit; y++) {
00394       for (x = 0; x < colcount; x++) {
00395          int i;
00396          struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
00397 
00398          if (y == 0) {
00399             char colname[256];
00400             SQLULEN maxcol;
00401 
00402             res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
00403             ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x);
00404             if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
00405                snprintf(colname, sizeof(colname), "field%d", x);
00406             }
00407 
00408             if (coldata->len < maxcol + 1) {
00409                ast_str_make_space(&coldata, maxcol + 1);
00410             }
00411 
00412             if (colnames->used) {
00413                ast_str_append(&colnames, 0, ",");
00414             }
00415             ast_str_make_space(&colnames, strlen(colname) * 2 + 1 + colnames->used);
00416 
00417             /* Copy data, encoding '\' and ',' for the argument parser */
00418             for (i = 0; i < sizeof(colname); i++) {
00419                if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) {
00420                   colnames->str[colnames->used++] = '\\';
00421                }
00422                colnames->str[colnames->used++] = colname[i];
00423 
00424                if (colname[i] == '\0') {
00425                   colnames->used--;
00426                   break;
00427                }
00428             }
00429 
00430             if (resultset) {
00431                void *tmp = ast_realloc(resultset, sizeof(*resultset) + colnames->used + 1);
00432                if (!tmp) {
00433                   ast_log(LOG_ERROR, "No space for a new resultset?\n");
00434                   ast_free(resultset);
00435                   SQLCloseCursor(stmt);
00436                   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00437                   ast_odbc_release_obj(obj);
00438                   pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00439                   if (chan)
00440                      ast_autoservice_stop(chan);
00441                   if (bogus_chan)
00442                      ast_channel_free(chan);
00443                   ast_free(sql);
00444                   return -1;
00445                }
00446                resultset = tmp;
00447                strcpy((char *)resultset + sizeof(*resultset), colnames->str);
00448             }
00449          }
00450 
00451          buflen = strlen(buf);
00452          res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata->str, coldata->len, &indicator);
00453          if (indicator == SQL_NULL_DATA) {
00454             ast_debug(3, "Got NULL data\n");
00455             ast_str_reset(coldata);
00456             res = SQL_SUCCESS;
00457          }
00458 
00459          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00460             ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql->str);
00461             y = -1;
00462             buf[0] = '\0';
00463             goto end_acf_read;
00464          }
00465 
00466          ast_debug(2, "Got coldata of '%s'\n", coldata->str);
00467          coldata->used = strlen(coldata->str);
00468 
00469          /* Copy data, encoding '\' and ',' for the argument parser */
00470          for (i = 0; i < coldata->used; i++) {
00471             if (escapecommas && (coldata->str[i] == '\\' || coldata->str[i] == ',')) {
00472                buf[buflen++] = '\\';
00473             }
00474             buf[buflen++] = coldata->str[i];
00475 
00476             if (buflen >= len - 2)
00477                break;
00478 
00479             if (coldata->str[i] == '\0')
00480                break;
00481          }
00482 
00483          buf[buflen++] = ',';
00484          buf[buflen] = '\0';
00485          ast_debug(2, "buf is now set to '%s'\n", buf);
00486       }
00487       /* Trim trailing comma */
00488       buf[buflen - 1] = '\0';
00489       ast_debug(2, "buf is now set to '%s'\n", buf);
00490 
00491       if (resultset) {
00492          row = ast_calloc(1, sizeof(*row) + buflen);
00493          if (!row) {
00494             ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
00495             goto end_acf_read;
00496          }
00497          strcpy((char *)row + sizeof(*row), buf);
00498          AST_LIST_INSERT_TAIL(resultset, row, list);
00499 
00500          /* Get next row */
00501          res = SQLFetch(stmt);
00502          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00503             if (res != SQL_NO_DATA)
00504                ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str);
00505             y++;
00506             break;
00507          }
00508       }
00509    }
00510 
00511 end_acf_read:
00512    snprintf(rowcount, sizeof(rowcount), "%d", y);
00513    pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
00514    pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames->str);
00515    if (resultset) {
00516       int uid;
00517       struct ast_datastore *odbc_store;
00518       uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
00519       snprintf(buf, len, "%d", uid);
00520       odbc_store = ast_datastore_alloc(&odbc_info, buf);
00521       if (!odbc_store) {
00522          ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel.  Results fail.\n");
00523          odbc_datastore_free(resultset);
00524          SQLCloseCursor(stmt);
00525          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00526          ast_odbc_release_obj(obj);
00527          if (chan)
00528             ast_autoservice_stop(chan);
00529          if (bogus_chan)
00530             ast_channel_free(chan);
00531          ast_free(sql);
00532          return -1;
00533       }
00534       odbc_store->data = resultset;
00535       ast_channel_datastore_add(chan, odbc_store);
00536    }
00537    SQLCloseCursor(stmt);
00538    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00539    ast_odbc_release_obj(obj);
00540    if (chan)
00541       ast_autoservice_stop(chan);
00542    if (bogus_chan)
00543       ast_channel_free(chan);
00544    ast_free(sql);
00545    return 0;
00546 }

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

Definition at line 130 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_free, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_create(), ast_str_make_space(), ast_strdupa, ast_strlen_zero(), buf, chan, dsn, generic_execute(), acf_odbc_query::list, LOG_ERROR, ast_custom_function::name, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), acf_odbc_query::sql_write, and acf_odbc_query::writehandle.

Referenced by init_acf_query().

00131 {
00132    struct odbc_obj *obj = NULL;
00133    struct acf_odbc_query *query;
00134    char *t, varname[15];
00135    int i, dsn, bogus_chan = 0;
00136    AST_DECLARE_APP_ARGS(values,
00137       AST_APP_ARG(field)[100];
00138    );
00139    AST_DECLARE_APP_ARGS(args,
00140       AST_APP_ARG(field)[100];
00141    );
00142    SQLHSTMT stmt = NULL;
00143    SQLLEN rows=0;
00144    struct ast_str *buf = ast_str_create(16);
00145 
00146    if (!buf) {
00147       return -1;
00148    }
00149 
00150    AST_RWLIST_RDLOCK(&queries);
00151    AST_RWLIST_TRAVERSE(&queries, query, list) {
00152       if (!strcmp(query->acf->name, cmd)) {
00153          break;
00154       }
00155    }
00156 
00157    if (!query) {
00158       ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
00159       AST_RWLIST_UNLOCK(&queries);
00160       ast_free(buf);
00161       return -1;
00162    }
00163 
00164    if (!chan) {
00165       if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc")))
00166          bogus_chan = 1;
00167    }
00168 
00169    if (chan)
00170       ast_autoservice_start(chan);
00171 
00172    ast_str_make_space(&buf, strlen(query->sql_write) * 2);
00173 
00174    /* Parse our arguments */
00175    t = value ? ast_strdupa(value) : "";
00176 
00177    if (!s || !t) {
00178       ast_log(LOG_ERROR, "Out of memory\n");
00179       AST_RWLIST_UNLOCK(&queries);
00180       if (chan)
00181          ast_autoservice_stop(chan);
00182       if (bogus_chan)
00183          ast_channel_free(chan);
00184       ast_free(buf);
00185       return -1;
00186    }
00187 
00188    AST_STANDARD_APP_ARGS(args, s);
00189    for (i = 0; i < args.argc; i++) {
00190       snprintf(varname, sizeof(varname), "ARG%d", i + 1);
00191       pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
00192    }
00193 
00194    /* Parse values, just like arguments */
00195    AST_STANDARD_APP_ARGS(values, t);
00196    for (i = 0; i < values.argc; i++) {
00197       snprintf(varname, sizeof(varname), "VAL%d", i + 1);
00198       pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
00199    }
00200 
00201    /* Additionally set the value as a whole (but push an empty string if value is NULL) */
00202    pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
00203 
00204    pbx_substitute_variables_helper(chan, query->sql_write, buf->str, buf->len - 1);
00205 
00206    /* Restore prior values */
00207    for (i = 0; i < args.argc; i++) {
00208       snprintf(varname, sizeof(varname), "ARG%d", i + 1);
00209       pbx_builtin_setvar_helper(chan, varname, NULL);
00210    }
00211 
00212    for (i = 0; i < values.argc; i++) {
00213       snprintf(varname, sizeof(varname), "VAL%d", i + 1);
00214       pbx_builtin_setvar_helper(chan, varname, NULL);
00215    }
00216    pbx_builtin_setvar_helper(chan, "VALUE", NULL);
00217 
00218    AST_RWLIST_UNLOCK(&queries);
00219 
00220    for (dsn = 0; dsn < 5; dsn++) {
00221       if (!ast_strlen_zero(query->writehandle[dsn])) {
00222          obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
00223          if (obj)
00224             stmt = ast_odbc_direct_execute(obj, generic_execute, buf->str);
00225       }
00226       if (stmt)
00227          break;
00228    }
00229 
00230    if (stmt) {
00231       /* Rows affected */
00232       SQLRowCount(stmt, &rows);
00233    }
00234 
00235    /* Output the affected rows, for all cases.  In the event of failure, we
00236     * flag this as -1 rows.  Note that this is different from 0 affected rows
00237     * which would be the case if we succeeded in our query, but the values did
00238     * not change. */
00239    snprintf(varname, sizeof(varname), "%d", (int)rows);
00240    pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
00241 
00242    if (stmt) {
00243       SQLCloseCursor(stmt);
00244       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00245    }
00246    if (obj)
00247       ast_odbc_release_obj(obj);
00248 
00249    if (chan)
00250       ast_autoservice_stop(chan);
00251    if (bogus_chan)
00252       ast_channel_free(chan);
00253    ast_free(buf);
00254 
00255    return 0;
00256 }

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

Definition at line 620 of file func_odbc.c.

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

Referenced by load_module().

00621 {
00622    struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data);
00623    if (!store) /* Already freed; no big deal. */
00624       return 0;
00625    ast_channel_datastore_remove(chan, store);
00626    ast_datastore_free(store);
00627    return 0;
00628 }

static int free_acf_query ( struct acf_odbc_query query  )  [static]

Definition at line 818 of file func_odbc.c.

References acf_odbc_query::acf, ast_free, ast_custom_function::desc, ast_custom_function::name, and ast_custom_function::syntax.

Referenced by reload(), and unload_module().

00819 {
00820    if (query) {
00821       if (query->acf) {
00822          if (query->acf->name)
00823             ast_free((char *)query->acf->name);
00824          if (query->acf->syntax)
00825             ast_free((char *)query->acf->syntax);
00826          if (query->acf->desc)
00827             ast_free((char *)query->acf->desc);
00828          ast_free(query->acf);
00829       }
00830       ast_free(query);
00831    }
00832    return 0;
00833 }

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

Definition at line 104 of file func_odbc.c.

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

Referenced by acf_odbc_read(), and acf_odbc_write().

00105 {
00106    int res;
00107    char *sql = data;
00108    SQLHSTMT stmt;
00109 
00110    res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00111    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00112       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00113       return NULL;
00114    }
00115 
00116    res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS);
00117    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00118       ast_log(LOG_WARNING, "SQL Exec Direct failed![%s]\n", sql);
00119       SQLCloseCursor(stmt);
00120       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00121       return NULL;
00122    }
00123 
00124    return stmt;
00125 }

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

Definition at line 630 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_strlen_zero(), ast_variable_retrieve(), dsn, errno, LOG_WARNING, OPT_ESCAPECOMMAS, OPT_MULTIROW, ast_custom_function::read, and ast_custom_function::synopsis.

Referenced by load_module(), and reload().

00631 {
00632    const char *tmp;
00633    int i;
00634    int res;
00635 
00636    if (!cfg || !catg) {
00637       return EINVAL;
00638    }
00639 
00640    *query = ast_calloc(1, sizeof(struct acf_odbc_query));
00641    if (! (*query))
00642       return ENOMEM;
00643 
00644    if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
00645       char *tmp2 = ast_strdupa(tmp);
00646       AST_DECLARE_APP_ARGS(writeconf,
00647          AST_APP_ARG(dsn)[5];
00648       );
00649       AST_STANDARD_APP_ARGS(writeconf, tmp2);
00650       for (i = 0; i < 5; i++) {
00651          if (!ast_strlen_zero(writeconf.dsn[i]))
00652             ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
00653       }
00654    }
00655 
00656    if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
00657       char *tmp2 = ast_strdupa(tmp);
00658       AST_DECLARE_APP_ARGS(readconf,
00659          AST_APP_ARG(dsn)[5];
00660       );
00661       AST_STANDARD_APP_ARGS(readconf, tmp2);
00662       for (i = 0; i < 5; i++) {
00663          if (!ast_strlen_zero(readconf.dsn[i]))
00664             ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
00665       }
00666    } else {
00667       /* If no separate readhandle, then use the writehandle for reading */
00668       for (i = 0; i < 5; i++) {
00669          if (!ast_strlen_zero((*query)->writehandle[i]))
00670             ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
00671       }
00672    }
00673 
00674    if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")))
00675       ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00676    else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) {
00677       ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s.  Please use 'readsql' instead.\n", catg);
00678       ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
00679    }
00680 
00681    if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) {
00682       ast_free(*query);
00683       *query = NULL;
00684       ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
00685       return EINVAL;
00686    }
00687 
00688    if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")))
00689       ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00690    else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) {
00691       ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s.  Please use 'writesql' instead.\n", catg);
00692       ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
00693    }
00694 
00695    if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) {
00696       ast_free(*query);
00697       *query = NULL;
00698       ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
00699       return EINVAL;
00700    }
00701 
00702    /* Allow escaping of embedded commas in fields to be turned off */
00703    ast_set_flag((*query), OPT_ESCAPECOMMAS);
00704    if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
00705       if (ast_false(tmp))
00706          ast_clear_flag((*query), OPT_ESCAPECOMMAS);
00707    }
00708 
00709    if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
00710       if (strcasecmp(tmp, "multirow") == 0)
00711          ast_set_flag((*query), OPT_MULTIROW);
00712       if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
00713          sscanf(tmp, "%d", &((*query)->rowlimit));
00714    }
00715 
00716    (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
00717    if (! (*query)->acf) {
00718       ast_free(*query);
00719       *query = NULL;
00720       return ENOMEM;
00721    }
00722 
00723    if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
00724       if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
00725          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00726       }
00727    } else {
00728       if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
00729          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00730       }
00731    }
00732 
00733    if (!((*query)->acf->name)) {
00734       ast_free((*query)->acf);
00735       ast_free(*query);
00736       *query = NULL;
00737       return ENOMEM;
00738    }
00739 
00740    if (asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name) < 0) {
00741       ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00742       (*query)->acf->syntax = NULL;
00743    }
00744 
00745    if (!((*query)->acf->syntax)) {
00746       ast_free((char *)(*query)->acf->name);
00747       ast_free((*query)->acf);
00748       ast_free(*query);
00749       *query = NULL;
00750       return ENOMEM;
00751    }
00752 
00753    (*query)->acf->synopsis = "Runs the referenced query with the specified arguments";
00754 
00755    res = 0;
00756    if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) {
00757       res = asprintf((char **)&((*query)->acf->desc),
00758                 "Runs the following query, as defined in func_odbc.conf, performing\n"
00759                 "substitution of the arguments into the query as specified by ${ARG1},\n"
00760                 "${ARG2}, ... ${ARGn}.  When setting the function, the values are provided\n"
00761                 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
00762                 "\nRead:\n%s\n\nWrite:\n%s\n",
00763                 (*query)->sql_read,
00764                 (*query)->sql_write);
00765    } else if (!ast_strlen_zero((*query)->sql_read)) {
00766       res = asprintf((char **)&((*query)->acf->desc),
00767                 "Runs the following query, as defined in func_odbc.conf, performing\n"
00768                 "substitution of the arguments into the query as specified by ${ARG1},\n"
00769                 "${ARG2}, ... ${ARGn}.  This function may only be read, not set.\n\nSQL:\n%s\n",
00770                 (*query)->sql_read);
00771    } else if (!ast_strlen_zero((*query)->sql_write)) {
00772       res = asprintf((char **)&((*query)->acf->desc),
00773                 "Runs the following query, as defined in func_odbc.conf, performing\n"
00774                 "substitution of the arguments into the query as specified by ${ARG1},\n"
00775                 "${ARG2}, ... ${ARGn}.  The values are provided either in whole as\n"
00776                 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
00777                 "This function may only be set.\nSQL:\n%s\n",
00778                 (*query)->sql_write);
00779    } else {
00780       ast_free((char *)(*query)->acf->syntax);
00781       ast_free((char *)(*query)->acf->name);
00782       ast_free((*query)->acf);
00783       ast_free(*query);
00784       ast_log(LOG_WARNING, "Section %s was found, but there was no SQL to execute.  Ignoring.\n", catg);
00785       return EINVAL;
00786    }
00787 
00788    if (res < 0) {
00789       ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00790       (*query)->acf->desc = NULL;
00791    }
00792 
00793 
00794    if (!((*query)->acf->desc)) {
00795       ast_free((char *)(*query)->acf->syntax);
00796       ast_free((char *)(*query)->acf->name);
00797       ast_free((*query)->acf);
00798       ast_free(*query);
00799       *query = NULL;
00800       return ENOMEM;
00801    }
00802 
00803    if (ast_strlen_zero((*query)->sql_read)) {
00804       (*query)->acf->read = NULL;
00805    } else {
00806       (*query)->acf->read = acf_odbc_read;
00807    }
00808 
00809    if (ast_strlen_zero((*query)->sql_write)) {
00810       (*query)->acf->write = NULL;
00811    } else {
00812       (*query)->acf->write = acf_odbc_write;
00813    }
00814 
00815    return 0;
00816 }

static int load_module ( void   )  [static]

Definition at line 835 of file func_odbc.c.

References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, config_flags, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), and LOG_NOTICE.

00836 {
00837    int res = 0;
00838    struct ast_config *cfg;
00839    char *catg;
00840    struct ast_flags config_flags = { 0 };
00841 
00842    res |= ast_custom_function_register(&fetch_function);
00843    res |= ast_register_application(app_odbcfinish, exec_odbcfinish, syn_odbcfinish, desc_odbcfinish);
00844    AST_RWLIST_WRLOCK(&queries);
00845 
00846    cfg = ast_config_load(config, config_flags);
00847    if (!cfg) {
00848       ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
00849       AST_RWLIST_UNLOCK(&queries);
00850       return AST_MODULE_LOAD_DECLINE;
00851    }
00852 
00853    for (catg = ast_category_browse(cfg, NULL);
00854         catg;
00855         catg = ast_category_browse(cfg, catg)) {
00856       struct acf_odbc_query *query = NULL;
00857       int err;
00858 
00859       if ((err = init_acf_query(cfg, catg, &query))) {
00860          if (err == ENOMEM)
00861             ast_log(LOG_ERROR, "Out of memory\n");
00862          else if (err == EINVAL)
00863             ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
00864          else
00865             ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
00866       } else {
00867          AST_RWLIST_INSERT_HEAD(&queries, query, list);
00868          ast_custom_function_register(query->acf);
00869       }
00870    }
00871 
00872    ast_config_destroy(cfg);
00873    res |= ast_custom_function_register(&escape_function);
00874 
00875    AST_RWLIST_UNLOCK(&queries);
00876    return res;
00877 }

static void odbc_datastore_free ( void *  data  )  [static]

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

00092 {
00093    struct odbc_datastore *result = data;
00094    struct odbc_datastore_row *row;
00095    AST_LIST_LOCK(result);
00096    while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
00097       ast_free(row);
00098    }
00099    AST_LIST_UNLOCK(result);
00100    AST_LIST_HEAD_DESTROY(result);
00101    ast_free(result);
00102 }

static int reload ( void   )  [static]

Definition at line 904 of file func_odbc.c.

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

00905 {
00906    int res = 0;
00907    struct ast_config *cfg;
00908    struct acf_odbc_query *oldquery;
00909    char *catg;
00910    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
00911 
00912    cfg = ast_config_load(config, config_flags);
00913    if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00914       return 0;
00915 
00916    AST_RWLIST_WRLOCK(&queries);
00917 
00918    while (!AST_RWLIST_EMPTY(&queries)) {
00919       oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
00920       ast_custom_function_unregister(oldquery->acf);
00921       free_acf_query(oldquery);
00922    }
00923 
00924    if (!cfg) {
00925       ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
00926       goto reload_out;
00927    }
00928 
00929    for (catg = ast_category_browse(cfg, NULL);
00930         catg;
00931         catg = ast_category_browse(cfg, catg)) {
00932       struct acf_odbc_query *query = NULL;
00933 
00934       if (init_acf_query(cfg, catg, &query)) {
00935          ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
00936       } else {
00937          AST_RWLIST_INSERT_HEAD(&queries, query, list);
00938          ast_custom_function_register(query->acf);
00939       }
00940    }
00941 
00942    ast_config_destroy(cfg);
00943 reload_out:
00944    AST_RWLIST_UNLOCK(&queries);
00945    return res;
00946 }

static int unload_module ( void   )  [static]

Definition at line 879 of file func_odbc.c.

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

00880 {
00881    struct acf_odbc_query *query;
00882    int res = 0;
00883 
00884    AST_RWLIST_WRLOCK(&queries);
00885    while (!AST_RWLIST_EMPTY(&queries)) {
00886       query = AST_RWLIST_REMOVE_HEAD(&queries, list);
00887       ast_custom_function_unregister(query->acf);
00888       free_acf_query(query);
00889    }
00890 
00891    res |= ast_custom_function_unregister(&escape_function);
00892    res |= ast_custom_function_unregister(&fetch_function);
00893    res |= ast_unregister_application(app_odbcfinish);
00894 
00895    /* Allow any threads waiting for this lock to pass (avoids a race) */
00896    AST_RWLIST_UNLOCK(&queries);
00897    usleep(1);
00898    AST_RWLIST_WRLOCK(&queries);
00899 
00900    AST_RWLIST_UNLOCK(&queries);
00901    return 0;
00902 }


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

Definition at line 954 of file func_odbc.c.

char* app_odbcfinish = "ODBCFinish" [static]

Definition at line 613 of file func_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 954 of file func_odbc.c.

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

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

Referenced by acf_odbc_read().

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

Definition at line 47 of file func_odbc.c.

char* desc_odbcfinish [static]

Initial value:

"ODBCFinish(<result-id>)\n"
"  Clears any remaining rows of the specified resultset\n"

Definition at line 615 of file func_odbc.c.

struct ast_custom_function escape_function [static]

Definition at line 564 of file func_odbc.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function fetch_function [static]

Definition at line 601 of file func_odbc.c.

Referenced by load_module(), and unload_module().

struct ast_datastore_info odbc_info

Initial value:

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

Definition at line 67 of file func_odbc.c.

Referenced by acf_fetch(), and exec_odbcfinish().

enum { ... } odbc_option_flags

int resultcount = 0 [static]

Definition at line 86 of file func_odbc.c.

char* syn_odbcfinish = "Clear the resultset of a successful multirow query" [static]

Definition at line 614 of file func_odbc.c.


Generated on Fri Jun 19 12:10:37 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7