Thu Jul 9 13:41:20 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 __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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static char * app_odbcfinish = "ODBCFinish"
static const struct ast_module_infoast_module_info = &__mod_info
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 __reg_module ( void   )  [static]

Definition at line 915 of file func_odbc.c.

static void __unreg_module ( void   )  [static]

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

00510 {
00511    char *out = buf;
00512 
00513    for (; *data && out - buf < len; data++) {
00514       if (*data == '\'') {
00515          *out = '\'';
00516          out++;
00517       }
00518       *out++ = *data;
00519    }
00520    *out = '\0';
00521 
00522    return 0;
00523 }

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

Definition at line 537 of file func_odbc.c.

References ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_copy_string(), 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().

00538 {
00539    struct ast_datastore *store;
00540    struct odbc_datastore *resultset;
00541    struct odbc_datastore_row *row;
00542    store = ast_channel_datastore_find(chan, &odbc_info, data);
00543    if (!store) {
00544       return -1;
00545    }
00546    resultset = store->data;
00547    AST_LIST_LOCK(resultset);
00548    row = AST_LIST_REMOVE_HEAD(resultset, list);
00549    AST_LIST_UNLOCK(resultset);
00550    if (!row) {
00551       /* Cleanup datastore */
00552       ast_channel_datastore_remove(chan, store);
00553       ast_channel_datastore_free(store);
00554       return -1;
00555    }
00556    pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
00557    ast_copy_string(buf, row->data, len);
00558    ast_free(row);
00559    return 0;
00560 }

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

Definition at line 245 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_LIST_HEAD_INIT, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_test_flag, chan, dsn, generic_execute(), 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, and acf_odbc_query::sql_read.

Referenced by init_acf_query().

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

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

Definition at line 127 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_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_STANDARD_APP_ARGS, 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().

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

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

Definition at line 581 of file func_odbc.c.

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

Referenced by load_module().

00582 {
00583    struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data);
00584    if (!store) /* Already freed; no big deal. */
00585       return 0;
00586    ast_channel_datastore_remove(chan, store);
00587    ast_channel_datastore_free(store);
00588    return 0;
00589 }

static int free_acf_query ( struct acf_odbc_query query  )  [static]

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

00780 {
00781    if (query) {
00782       if (query->acf) {
00783          if (query->acf->name)
00784             ast_free((char *)query->acf->name);
00785          if (query->acf->syntax)
00786             ast_free((char *)query->acf->syntax);
00787          if (query->acf->desc)
00788             ast_free((char *)query->acf->desc);
00789          ast_free(query->acf);
00790       }
00791       ast_free(query);
00792    }
00793    return 0;
00794 }

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

Definition at line 101 of file func_odbc.c.

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

Referenced by acf_odbc_read(), and acf_odbc_write().

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

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

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

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

static int load_module ( void   )  [static]

Definition at line 796 of file func_odbc.c.

References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), and LOG_NOTICE.

00797 {
00798    int res = 0;
00799    struct ast_config *cfg;
00800    char *catg;
00801    struct ast_flags config_flags = { 0 };
00802 
00803    res |= ast_custom_function_register(&fetch_function);
00804    res |= ast_register_application(app_odbcfinish, exec_odbcfinish, syn_odbcfinish, desc_odbcfinish);
00805    AST_LIST_LOCK(&queries);
00806 
00807    cfg = ast_config_load(config, config_flags);
00808    if (!cfg) {
00809       ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
00810       AST_LIST_UNLOCK(&queries);
00811       return AST_MODULE_LOAD_DECLINE;
00812    }
00813 
00814    for (catg = ast_category_browse(cfg, NULL);
00815         catg;
00816         catg = ast_category_browse(cfg, catg)) {
00817       struct acf_odbc_query *query = NULL;
00818       int err;
00819 
00820       if ((err = init_acf_query(cfg, catg, &query))) {
00821          if (err == ENOMEM)
00822             ast_log(LOG_ERROR, "Out of memory\n");
00823          else if (err == EINVAL)
00824             ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
00825          else
00826             ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
00827       } else {
00828          AST_LIST_INSERT_HEAD(&queries, query, list);
00829          ast_custom_function_register(query->acf);
00830       }
00831    }
00832 
00833    ast_config_destroy(cfg);
00834    res |= ast_custom_function_register(&escape_function);
00835 
00836    AST_LIST_UNLOCK(&queries);
00837    return res;
00838 }

static void odbc_datastore_free ( void *  data  )  [static]

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

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

static int reload ( void   )  [static]

Definition at line 865 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_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, free_acf_query(), init_acf_query(), and LOG_WARNING.

00866 {
00867    int res = 0;
00868    struct ast_config *cfg;
00869    struct acf_odbc_query *oldquery;
00870    char *catg;
00871    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
00872 
00873    cfg = ast_config_load(config, config_flags);
00874    if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00875       return 0;
00876 
00877    AST_LIST_LOCK(&queries);
00878 
00879    while (!AST_LIST_EMPTY(&queries)) {
00880       oldquery = AST_LIST_REMOVE_HEAD(&queries, list);
00881       ast_custom_function_unregister(oldquery->acf);
00882       free_acf_query(oldquery);
00883    }
00884 
00885    if (!cfg) {
00886       ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
00887       goto reload_out;
00888    }
00889 
00890    for (catg = ast_category_browse(cfg, NULL);
00891         catg;
00892         catg = ast_category_browse(cfg, catg)) {
00893       struct acf_odbc_query *query = NULL;
00894 
00895       if (init_acf_query(cfg, catg, &query)) {
00896          ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
00897       } else {
00898          AST_LIST_INSERT_HEAD(&queries, query, list);
00899          ast_custom_function_register(query->acf);
00900       }
00901    }
00902 
00903    ast_config_destroy(cfg);
00904 reload_out:
00905    AST_LIST_UNLOCK(&queries);
00906    return res;
00907 }

static int unload_module ( void   )  [static]

Definition at line 840 of file func_odbc.c.

References acf_odbc_query::acf, ast_custom_function_unregister(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_unregister_application(), escape_function, fetch_function, free_acf_query(), and acf_odbc_query::list.

00841 {
00842    struct acf_odbc_query *query;
00843    int res = 0;
00844 
00845    AST_LIST_LOCK(&queries);
00846    while (!AST_LIST_EMPTY(&queries)) {
00847       query = AST_LIST_REMOVE_HEAD(&queries, list);
00848       ast_custom_function_unregister(query->acf);
00849       free_acf_query(query);
00850    }
00851 
00852    res |= ast_custom_function_unregister(&escape_function);
00853    res |= ast_custom_function_unregister(&fetch_function);
00854    res |= ast_unregister_application(app_odbcfinish);
00855 
00856    /* Allow any threads waiting for this lock to pass (avoids a race) */
00857    AST_LIST_UNLOCK(&queries);
00858    usleep(1);
00859    AST_LIST_LOCK(&queries);
00860 
00861    AST_LIST_UNLOCK(&queries);
00862    return 0;
00863 }


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

Definition at line 915 of file func_odbc.c.

char* app_odbcfinish = "ODBCFinish" [static]

Definition at line 574 of file func_odbc.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 915 of file func_odbc.c.

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

struct ast_custom_function escape_function [static]

Definition at line 525 of file func_odbc.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function fetch_function [static]

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


Generated on Thu Jul 9 13:41:20 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7