Thu Oct 11 06:37:02 2012

Asterisk developer's documentation


res_config_odbc.c File Reference

odbc+odbc plugin for portable configuration engine More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/utils.h"
#include "asterisk/stringfields.h"

Include dependency graph for res_config_odbc.c:

Go to the source code of this file.

Data Structures

struct  config_odbc_obj
struct  custom_prepare_struct
struct  update2_prepare_struct

Defines

#define CHECK_SIZE(n)
#define warn_length(col, size)   ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is not long enough to contain realtime data (needs %d)\n", table, database, col->name, size)
#define warn_type(col, type)   ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is of the incorrect type (%d) to contain the required realtime data\n", table, database, col->name, col->type)
#define WARN_TYPE_OR_LENGTH(n)

Functions

static void __init_sql_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
static struct ast_configconfig_odbc (const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
static SQLHSTMT config_odbc_prepare (struct odbc_obj *obj, void *data)
static SQLHSTMT custom_prepare (struct odbc_obj *obj, void *data)
static void decode_chunk (char *chunk)
static int destroy_odbc (const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 Excute an DELETE query.
static int load_module (void)
static struct ast_configrealtime_multi_odbc (const char *database, const char *table, va_list ap)
 Excute an Select query and return ast_config list.
static struct ast_variablerealtime_odbc (const char *database, const char *table, va_list ap)
 Excute an SQL query and return ast_variable list.
static int reload_module (void)
static int require_odbc (const char *database, const char *table, va_list ap)
static int store_odbc (const char *database, const char *table, va_list ap)
 Excute an INSERT query.
static int unload_module (void)
static int unload_odbc (const char *a, const char *b)
static int update2_odbc (const char *database, const char *table, va_list ap)
 Execute an UPDATE query.
static SQLHSTMT update2_prepare (struct odbc_obj *obj, void *data)
static int update_odbc (const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 Excute an UPDATE query.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime ODBC configuration" , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_config_engine odbc_engine
static struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }


Detailed Description

odbc+odbc plugin for portable configuration engine

Author:
Mark Spencer <markster@digium.com>

Anthony Minessale II <anthmct@yahoo.com>

Definition in file res_config_odbc.c.


Define Documentation

#define CHECK_SIZE (  ) 

Value:

if (col->size < n) {      \
                     warn_length(col, n);  \
                  }                         \
                  break;

Referenced by require_odbc().

#define warn_length ( col,
size   )     ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is not long enough to contain realtime data (needs %d)\n", table, database, col->name, size)

Definition at line 990 of file res_config_odbc.c.

Referenced by require_odbc().

#define warn_type ( col,
type   )     ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is of the incorrect type (%d) to contain the required realtime data\n", table, database, col->name, col->type)

Definition at line 991 of file res_config_odbc.c.

Referenced by require_odbc().

#define WARN_TYPE_OR_LENGTH (  ) 

Value:

if (!ast_rq_is_int(type)) {  \
                     warn_type(col, type);    \
                  } else {                     \
                     warn_length(col, n);  \
                  }

Referenced by require_odbc().


Function Documentation

static void __init_sql_buf ( void   )  [static]

Definition at line 50 of file res_config_odbc.c.

00052 {

static void __reg_module ( void   )  [static]

Definition at line 1193 of file res_config_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 1193 of file res_config_odbc.c.

static struct ast_config* config_odbc ( const char *  database,
const char *  table,
const char *  file,
struct ast_config cfg,
struct ast_flags  flags,
const char *  sugg_incl,
const char *  who_asked 
) [static, read]

Definition at line 905 of file res_config_odbc.c.

References ast_build_string(), ast_category_append(), ast_category_new(), ast_config_get_current_category(), ast_config_internal_load(), ast_log(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_variable_append(), ast_variable_new(), config_odbc_obj::cat_metric, config_odbc_obj::category, config_odbc_prepare(), last, LOG_NOTICE, LOG_WARNING, RES_ODBC_CONNECTED, config_odbc_obj::sql, config_odbc_obj::var_name, and config_odbc_obj::var_val.

00906 {
00907    struct ast_variable *new_v;
00908    struct ast_category *cur_cat;
00909    int res = 0;
00910    struct odbc_obj *obj;
00911    char sqlbuf[1024] = "";
00912    char *sql = sqlbuf;
00913    size_t sqlleft = sizeof(sqlbuf);
00914    unsigned int last_cat_metric = 0;
00915    SQLSMALLINT rowcount = 0;
00916    SQLHSTMT stmt;
00917    char last[128] = "";
00918    struct config_odbc_obj q;
00919    struct ast_flags loader_flags = { 0 };
00920    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00921 
00922    memset(&q, 0, sizeof(q));
00923 
00924    if (!file || !strcmp (file, "res_config_odbc.conf"))
00925       return NULL;      /* cant configure myself with myself ! */
00926 
00927    obj = ast_odbc_request_obj2(database, connected_flag);
00928    if (!obj)
00929       return NULL;
00930 
00931    ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
00932    ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
00933    ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00934    q.sql = sqlbuf;
00935 
00936    stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
00937 
00938    if (!stmt) {
00939       ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
00940       ast_odbc_release_obj(obj);
00941       return NULL;
00942    }
00943 
00944    res = SQLNumResultCols(stmt, &rowcount);
00945 
00946    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00947       ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
00948       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00949       ast_odbc_release_obj(obj);
00950       return NULL;
00951    }
00952 
00953    if (!rowcount) {
00954       ast_log(LOG_NOTICE, "found nothing\n");
00955       ast_odbc_release_obj(obj);
00956       return cfg;
00957    }
00958 
00959    cur_cat = ast_config_get_current_category(cfg);
00960 
00961    while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
00962       if (!strcmp (q.var_name, "#include")) {
00963          if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
00964             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00965             ast_odbc_release_obj(obj);
00966             return NULL;
00967          }
00968          continue;
00969       } 
00970       if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
00971          cur_cat = ast_category_new(q.category, "", 99999);
00972          if (!cur_cat) {
00973             ast_log(LOG_WARNING, "Out of memory!\n");
00974             break;
00975          }
00976          strcpy(last, q.category);
00977          last_cat_metric   = q.cat_metric;
00978          ast_category_append(cfg, cur_cat);
00979       }
00980 
00981       new_v = ast_variable_new(q.var_name, q.var_val, "");
00982       ast_variable_append(cur_cat, new_v);
00983    }
00984 
00985    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00986    ast_odbc_release_obj(obj);
00987    return cfg;
00988 }

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

Definition at line 878 of file res_config_odbc.c.

References ast_verb, config_odbc_obj::cat_metric, config_odbc_obj::category, odbc_obj::con, config_odbc_obj::err, config_odbc_obj::sql, config_odbc_obj::var_name, and config_odbc_obj::var_val.

Referenced by config_odbc().

00879 {
00880    struct config_odbc_obj *q = data;
00881    SQLHSTMT sth;
00882    int res;
00883 
00884    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00885    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00886       ast_verb(4, "Failure in AllocStatement %d\n", res);
00887       return NULL;
00888    }
00889 
00890    res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00891    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00892       ast_verb(4, "Error in PREPARE %d\n", res);
00893       SQLFreeHandle(SQL_HANDLE_STMT, sth);
00894       return NULL;
00895    }
00896 
00897    SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
00898    SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
00899    SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
00900    SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
00901 
00902    return sth;
00903 }

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

Definition at line 72 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_debug, ast_log(), ast_string_field_set, ast_strlen_zero(), odbc_obj::con, custom_prepare_struct::encoding, encoding, custom_prepare_struct::extra, LOG_WARNING, custom_prepare_struct::skip, and custom_prepare_struct::sql.

Referenced by destroy_odbc(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().

00073 {
00074    int res, x = 1, count = 0;
00075    struct custom_prepare_struct *cps = data;
00076    const char *newparam, *newval;
00077    char encodebuf[1024];
00078    SQLHSTMT stmt;
00079    va_list ap;
00080 
00081    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00082    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00083       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00084       return NULL;
00085    }
00086 
00087    ast_debug(1, "Skip: %lld; SQL: %s\n", cps->skip, cps->sql);
00088 
00089    res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
00090    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00091       ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
00092       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00093       return NULL;
00094    }
00095 
00096    va_copy(ap, cps->ap);
00097    while ((newparam = va_arg(ap, const char *))) {
00098       newval = va_arg(ap, const char *);
00099       if ((1LL << count++) & cps->skip) {
00100          ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1LL << (count - 1), cps->skip);
00101          continue;
00102       }
00103       ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, newparam, newval);
00104       if (strchr(newval, ';') || strchr(newval, '^')) {
00105          char *eptr = encodebuf;
00106          const char *vptr = newval;
00107          for (; *vptr && eptr < encodebuf + sizeof(encodebuf); vptr++) {
00108             if (strchr("^;", *vptr)) {
00109                /* We use ^XX, instead of %XX because '%' is a special character in SQL */
00110                snprintf(eptr, encodebuf + sizeof(encodebuf) - eptr, "^%02hhX", *vptr);
00111                eptr += 3;
00112             } else {
00113                *eptr++ = *vptr;
00114             }
00115          }
00116          if (eptr < encodebuf + sizeof(encodebuf)) {
00117             *eptr = '\0';
00118          } else {
00119             encodebuf[sizeof(encodebuf) - 1] = '\0';
00120          }
00121          ast_string_field_set(cps, encoding[x], encodebuf);
00122          newval = cps->encoding[x];
00123       }
00124       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00125    }
00126    va_end(ap);
00127 
00128    if (!ast_strlen_zero(cps->extra))
00129       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(cps->extra), 0, (void *)cps->extra, 0, NULL);
00130    return stmt;
00131 }

static void decode_chunk ( char *  chunk  )  [static]

Definition at line 62 of file res_config_odbc.c.

Referenced by realtime_multi_odbc(), and realtime_odbc().

00063 {
00064    for (; *chunk; chunk++) {
00065       if (*chunk == '^' && strchr("0123456789ABCDEF", chunk[1]) && strchr("0123456789ABCDEF", chunk[2])) {
00066          sscanf(chunk + 1, "%02hhX", chunk);
00067          memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
00068       }
00069    }
00070 }

static int destroy_odbc ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
va_list  ap 
) [static]

Excute an DELETE query.

Parameters:
database 
table 
keyfield where clause field
lookup value of field for where clause
ap list containing one or more field/value set(s)
Delete a row from a database table, prepare the sql statement using keyfield and lookup control the number of records to change. Additional params to match rows are stored in ap list. Sub-in the values to the prepared statement and execute it.

Return values:
number of rows affected
-1 on failure

Definition at line 813 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_log(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, custom_prepare(), LOG_WARNING, RES_ODBC_CONNECTED, and custom_prepare_struct::sql.

00814 {
00815    struct odbc_obj *obj;
00816    SQLHSTMT stmt;
00817    char sql[256];
00818    SQLLEN rowcount=0;
00819    const char *newparam;
00820    int res;
00821    va_list aq;
00822    struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00823    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00824 
00825    if (!table) {
00826       return -1;
00827    }
00828 
00829    obj = ast_odbc_request_obj2(database, connected_flag);
00830    if (!obj) {
00831       return -1;
00832    }
00833 
00834    snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
00835 
00836    va_copy(aq, ap);
00837    while((newparam = va_arg(aq, const char *))) {
00838       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
00839       va_arg(aq, const char *);
00840    }
00841    va_end(aq);
00842    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
00843 
00844    va_copy(cps.ap, ap);
00845    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00846    va_end(cps.ap);
00847 
00848    if (!stmt) {
00849       ast_odbc_release_obj(obj);
00850       return -1;
00851    }
00852 
00853    res = SQLRowCount(stmt, &rowcount);
00854    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00855    ast_odbc_release_obj(obj);
00856 
00857    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00858       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00859       return -1;
00860    }
00861 
00862    if (rowcount >= 0)
00863       return (int)rowcount;
00864 
00865    return -1;
00866 }

static int load_module ( void   )  [static]

Definition at line 1176 of file res_config_odbc.c.

References ast_config_engine_register(), and ast_verb.

01177 {
01178    ast_config_engine_register(&odbc_engine);
01179    ast_verb(1, "res_config_odbc loaded.\n");
01180    return 0;
01181 }

static struct ast_config* realtime_multi_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static, read]

Excute an Select query and return ast_config list.

Parameters:
database 
table 
ap list containing one or more field/operator/value set.
Select database and preform query on table, prepare the sql statement Sub-in the values to the prepared statement and execute it. Execute this prepared query against several ODBC connected databases. Return results as an ast_config variable.

Return values:
var on success
NULL on failure

Definition at line 313 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_category_append(), ast_category_destroy(), ast_category_new(), ast_category_rename(), ast_config_new(), ast_log(), ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_strdupa, ast_string_field_free_memory, ast_string_field_init, ast_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new(), custom_prepare(), decode_chunk(), LOG_WARNING, RES_ODBC_CONNECTED, custom_prepare_struct::sql, strcasestr(), strsep(), and var.

00314 {
00315    struct odbc_obj *obj;
00316    SQLHSTMT stmt;
00317    char sql[1024];
00318    char coltitle[256];
00319    char rowdata[2048];
00320    const char *initfield;
00321    char *op;
00322    const char *newparam;
00323    char *stringp;
00324    char *chunk;
00325    SQLSMALLINT collen;
00326    int res;
00327    int x;
00328    struct ast_variable *var=NULL;
00329    struct ast_config *cfg=NULL;
00330    struct ast_category *cat=NULL;
00331    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00332    SQLULEN colsize;
00333    SQLSMALLINT colcount=0;
00334    SQLSMALLINT datatype;
00335    SQLSMALLINT decimaldigits;
00336    SQLSMALLINT nullable;
00337    SQLLEN indicator;
00338    struct custom_prepare_struct cps = { .sql = sql };
00339    va_list aq;
00340 
00341    if (!table || ast_string_field_init(&cps, 256)) {
00342       return NULL;
00343    }
00344 
00345 
00346    obj = ast_odbc_request_obj2(database, connected_flag);
00347    if (!obj) {
00348       ast_string_field_free_memory(&cps);
00349       return NULL;
00350    }
00351 
00352    va_copy(aq, ap);
00353    newparam = va_arg(aq, const char *);
00354    if (!newparam)  {
00355       va_end(aq);
00356       ast_odbc_release_obj(obj);
00357       ast_string_field_free_memory(&cps);
00358       return NULL;
00359    }
00360 
00361    initfield = ast_strdupa(newparam);
00362    if ((op = strchr(initfield, ' '))) {
00363       *op = '\0';
00364    }
00365 
00366    va_arg(aq, const char *);
00367    op = !strchr(newparam, ' ') ? " =" : "";
00368    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
00369       strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00370    while((newparam = va_arg(aq, const char *))) {
00371       op = !strchr(newparam, ' ') ? " =" : "";
00372       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
00373          strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00374       va_arg(aq, const char *);
00375    }
00376    va_end(aq);
00377 
00378    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00379 
00380    va_copy(cps.ap, ap);
00381    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00382    va_end(cps.ap);
00383 
00384    if (!stmt) {
00385       ast_odbc_release_obj(obj);
00386       ast_string_field_free_memory(&cps);
00387       return NULL;
00388    }
00389 
00390    res = SQLNumResultCols(stmt, &colcount);
00391    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00392       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00393       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00394       ast_odbc_release_obj(obj);
00395       ast_string_field_free_memory(&cps);
00396       return NULL;
00397    }
00398 
00399    cfg = ast_config_new();
00400    if (!cfg) {
00401       ast_log(LOG_WARNING, "Out of memory!\n");
00402       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00403       ast_odbc_release_obj(obj);
00404       ast_string_field_free_memory(&cps);
00405       return NULL;
00406    }
00407 
00408    while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
00409       var = NULL;
00410       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00411          ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00412          continue;
00413       }
00414       cat = ast_category_new("","",99999);
00415       if (!cat) {
00416          ast_log(LOG_WARNING, "Out of memory!\n");
00417          continue;
00418       }
00419       for (x=0;x<colcount;x++) {
00420          rowdata[0] = '\0';
00421          colsize = 0;
00422          collen = sizeof(coltitle);
00423          res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
00424                   &datatype, &colsize, &decimaldigits, &nullable);
00425          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00426             ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00427             ast_category_destroy(cat);
00428             goto next_sql_fetch;
00429          }
00430 
00431          indicator = 0;
00432          res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00433          if (indicator == SQL_NULL_DATA)
00434             continue;
00435 
00436          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00437             ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00438             ast_category_destroy(cat);
00439             goto next_sql_fetch;
00440          }
00441          stringp = rowdata;
00442          while (stringp) {
00443             chunk = strsep(&stringp, ";");
00444             if (!ast_strlen_zero(ast_strip(chunk))) {
00445                if (strchr(chunk, '^')) {
00446                   decode_chunk(chunk);
00447                }
00448                if (!strcmp(initfield, coltitle)) {
00449                   ast_category_rename(cat, chunk);
00450                }
00451                var = ast_variable_new(coltitle, chunk, "");
00452                ast_variable_append(cat, var);
00453             }
00454          }
00455       }
00456       ast_category_append(cfg, cat);
00457 next_sql_fetch:;
00458    }
00459 
00460    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00461    ast_odbc_release_obj(obj);
00462    ast_string_field_free_memory(&cps);
00463    return cfg;
00464 }

static struct ast_variable* realtime_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static, read]

Excute an SQL query and return ast_variable list.

Parameters:
database 
table 
ap list containing one or more field/operator/value set.
Select database and preform query on table, prepare the sql statement Sub-in the values to the prepared statement and execute it. Return results as a ast_variable list.

Return values:
var on success
NULL on failure

Definition at line 146 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_copy_string(), ast_log(), ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_string_field_free_memory, ast_string_field_init, ast_strip(), ast_strlen_zero(), ast_variable_new(), ast_variables_destroy(), custom_prepare(), decode_chunk(), LOG_ERROR, LOG_WARNING, RES_ODBC_CONNECTED, custom_prepare_struct::sql, strcasestr(), strsep(), and var.

00147 {
00148    struct odbc_obj *obj;
00149    SQLHSTMT stmt;
00150    char sql[1024];
00151    char coltitle[256];
00152    char rowdata[2048];
00153    char *op;
00154    const char *newparam;
00155    char *stringp;
00156    char *chunk;
00157    SQLSMALLINT collen;
00158    int res;
00159    int x;
00160    struct ast_variable *var=NULL, *prev=NULL;
00161    SQLULEN colsize;
00162    SQLSMALLINT colcount=0;
00163    SQLSMALLINT datatype;
00164    SQLSMALLINT decimaldigits;
00165    SQLSMALLINT nullable;
00166    SQLLEN indicator;
00167    va_list aq;
00168    struct custom_prepare_struct cps = { .sql = sql };
00169    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00170 
00171    if (ast_string_field_init(&cps, 256)) {
00172       return NULL;
00173    }
00174 
00175    if (!table) {
00176       ast_string_field_free_memory(&cps);
00177       return NULL;
00178    }
00179 
00180    obj = ast_odbc_request_obj2(database, connected_flag);
00181 
00182    if (!obj) {
00183       ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
00184       ast_string_field_free_memory(&cps);
00185       return NULL;
00186    }
00187 
00188    va_copy(aq, ap);
00189    newparam = va_arg(aq, const char *);
00190    if (!newparam) {
00191       va_end(aq);
00192       ast_odbc_release_obj(obj);
00193       ast_string_field_free_memory(&cps);
00194       return NULL;
00195    }
00196    va_arg(aq, const char *);
00197    op = !strchr(newparam, ' ') ? " =" : "";
00198    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
00199       strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00200    while((newparam = va_arg(aq, const char *))) {
00201       op = !strchr(newparam, ' ') ? " =" : "";
00202       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
00203          strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00204       va_arg(aq, const char *);
00205    }
00206    va_end(aq);
00207 
00208    va_copy(cps.ap, ap);
00209    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00210    va_end(cps.ap);
00211 
00212    if (!stmt) {
00213       ast_odbc_release_obj(obj);
00214       ast_string_field_free_memory(&cps);
00215       return NULL;
00216    }
00217 
00218    res = SQLNumResultCols(stmt, &colcount);
00219    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00220       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00221       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00222       ast_odbc_release_obj(obj);
00223       ast_string_field_free_memory(&cps);
00224       return NULL;
00225    }
00226 
00227    res = SQLFetch(stmt);
00228    if (res == SQL_NO_DATA) {
00229       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00230       ast_odbc_release_obj(obj);
00231       ast_string_field_free_memory(&cps);
00232       return NULL;
00233    }
00234    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00235       ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00236       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00237       ast_odbc_release_obj(obj);
00238       ast_string_field_free_memory(&cps);
00239       return NULL;
00240    }
00241    for (x = 0; x < colcount; x++) {
00242       rowdata[0] = '\0';
00243       colsize = 0;
00244       collen = sizeof(coltitle);
00245       res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
00246                &datatype, &colsize, &decimaldigits, &nullable);
00247       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00248          ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00249          if (var)
00250             ast_variables_destroy(var);
00251          ast_odbc_release_obj(obj);
00252          ast_string_field_free_memory(&cps);
00253          return NULL;
00254       }
00255 
00256       indicator = 0;
00257       res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00258       if (indicator == SQL_NULL_DATA)
00259          rowdata[0] = '\0';
00260       else if (ast_strlen_zero(rowdata)) {
00261          /* Because we encode the empty string for a NULL, we will encode
00262           * actual empty strings as a string containing a single whitespace. */
00263          ast_copy_string(rowdata, " ", sizeof(rowdata));
00264       }
00265 
00266       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00267          ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00268          if (var)
00269             ast_variables_destroy(var);
00270          ast_odbc_release_obj(obj);
00271          return NULL;
00272       }
00273       stringp = rowdata;
00274       while (stringp) {
00275          chunk = strsep(&stringp, ";");
00276          if (!ast_strlen_zero(ast_strip(chunk))) {
00277             if (strchr(chunk, '^')) {
00278                decode_chunk(chunk);
00279             }
00280             if (prev) {
00281                prev->next = ast_variable_new(coltitle, chunk, "");
00282                if (prev->next) {
00283                   prev = prev->next;
00284                }
00285             } else {
00286                prev = var = ast_variable_new(coltitle, chunk, "");
00287             }
00288          }
00289       }
00290    }
00291 
00292 
00293    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00294    ast_odbc_release_obj(obj);
00295    ast_string_field_free_memory(&cps);
00296    return var;
00297 }

static int reload_module ( void   )  [static]

Definition at line 1183 of file res_config_odbc.c.

01184 {
01185    return 0;
01186 }

static int require_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Definition at line 993 of file res_config_odbc.c.

References ast_log(), ast_odbc_find_table(), ast_rq_is_int(), AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CHECK_SIZE, odbc_cache_tables::columns, odbc_cache_columns::list, LOG_WARNING, odbc_cache_columns::name, RQ_CHAR, RQ_DATE, RQ_DATETIME, RQ_FLOAT, RQ_INTEGER1, RQ_INTEGER2, RQ_INTEGER3, RQ_INTEGER4, RQ_INTEGER8, RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, RQ_UINTEGER8, odbc_cache_columns::size, odbc_cache_columns::type, type, warn_length, warn_type, and WARN_TYPE_OR_LENGTH.

00994 {
00995    struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
00996    struct odbc_cache_columns *col;
00997    char *elm;
00998    int type, size;
00999 
01000    if (!tableptr) {
01001       return -1;
01002    }
01003 
01004    while ((elm = va_arg(ap, char *))) {
01005       type = va_arg(ap, require_type);
01006       size = va_arg(ap, int);
01007       /* Check if the field matches the criteria */
01008       AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
01009          if (strcmp(col->name, elm) == 0) {
01010             /* Type check, first.  Some fields are more particular than others */
01011             switch (col->type) {
01012             case SQL_CHAR:
01013             case SQL_VARCHAR:
01014             case SQL_LONGVARCHAR:
01015 #ifdef HAVE_ODBC_WCHAR
01016             case SQL_WCHAR:
01017             case SQL_WVARCHAR:
01018             case SQL_WLONGVARCHAR:
01019 #endif
01020             case SQL_BINARY:
01021             case SQL_VARBINARY:
01022             case SQL_LONGVARBINARY:
01023             case SQL_GUID:
01024 #define CHECK_SIZE(n) \
01025                   if (col->size < n) {      \
01026                      warn_length(col, n);  \
01027                   }                         \
01028                   break;
01029                switch (type) {
01030                case RQ_UINTEGER1: CHECK_SIZE(3)  /*         255 */
01031                case RQ_INTEGER1:  CHECK_SIZE(4)  /*        -128 */
01032                case RQ_UINTEGER2: CHECK_SIZE(5)  /*       65535 */
01033                case RQ_INTEGER2:  CHECK_SIZE(6)  /*      -32768 */
01034                case RQ_UINTEGER3:                /*    16777215 */
01035                case RQ_INTEGER3:  CHECK_SIZE(8)  /*    -8388608 */
01036                case RQ_DATE:                     /*  2008-06-09 */
01037                case RQ_UINTEGER4: CHECK_SIZE(10) /*  4200000000 */
01038                case RQ_INTEGER4:  CHECK_SIZE(11) /* -2100000000 */
01039                case RQ_DATETIME:                 /* 2008-06-09 16:03:47 */
01040                case RQ_UINTEGER8: CHECK_SIZE(19) /* trust me    */
01041                case RQ_INTEGER8:  CHECK_SIZE(20) /* ditto       */
01042                case RQ_FLOAT:
01043                case RQ_CHAR:      CHECK_SIZE(size)
01044                }
01045 #undef CHECK_SIZE
01046                break;
01047             case SQL_TYPE_DATE:
01048                if (type != RQ_DATE) {
01049                   warn_type(col, type);
01050                }
01051                break;
01052             case SQL_TYPE_TIMESTAMP:
01053             case SQL_TIMESTAMP:
01054                if (type != RQ_DATE && type != RQ_DATETIME) {
01055                   warn_type(col, type);
01056                }
01057                break;
01058             case SQL_BIT:
01059                warn_length(col, size);
01060                break;
01061 #define WARN_TYPE_OR_LENGTH(n)   \
01062                   if (!ast_rq_is_int(type)) {  \
01063                      warn_type(col, type);    \
01064                   } else {                     \
01065                      warn_length(col, n);  \
01066                   }
01067             case SQL_TINYINT:
01068                if (type != RQ_UINTEGER1) {
01069                   WARN_TYPE_OR_LENGTH(size)
01070                }
01071                break;
01072             case SQL_C_STINYINT:
01073                if (type != RQ_INTEGER1) {
01074                   WARN_TYPE_OR_LENGTH(size)
01075                }
01076                break;
01077             case SQL_C_USHORT:
01078                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
01079                   WARN_TYPE_OR_LENGTH(size)
01080                }
01081                break;
01082             case SQL_SMALLINT:
01083             case SQL_C_SSHORT:
01084                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
01085                   WARN_TYPE_OR_LENGTH(size)
01086                }
01087                break;
01088             case SQL_C_ULONG:
01089                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01090                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01091                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01092                   type != RQ_INTEGER4) {
01093                   WARN_TYPE_OR_LENGTH(size)
01094                }
01095                break;
01096             case SQL_INTEGER:
01097             case SQL_C_SLONG:
01098                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01099                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01100                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01101                   type != RQ_INTEGER4) {
01102                   WARN_TYPE_OR_LENGTH(size)
01103                }
01104                break;
01105             case SQL_C_UBIGINT:
01106                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01107                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01108                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01109                   type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
01110                   type != RQ_INTEGER8) {
01111                   WARN_TYPE_OR_LENGTH(size)
01112                }
01113                break;
01114             case SQL_BIGINT:
01115             case SQL_C_SBIGINT:
01116                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01117                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01118                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01119                   type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
01120                   type != RQ_INTEGER8) {
01121                   WARN_TYPE_OR_LENGTH(size)
01122                }
01123                break;
01124 #undef WARN_TYPE_OR_LENGTH
01125             case SQL_NUMERIC:
01126             case SQL_DECIMAL:
01127             case SQL_FLOAT:
01128             case SQL_REAL:
01129             case SQL_DOUBLE:
01130                if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
01131                   warn_type(col, type);
01132                }
01133                break;
01134             default:
01135                ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm);
01136             }
01137             break;
01138          }
01139       }
01140       if (!col) {
01141          ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
01142       }
01143    }
01144    AST_RWLIST_UNLOCK(&tableptr->columns);
01145    return 0;
01146 }

static int store_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Excute an INSERT query.

Parameters:
database 
table 
ap list containing one or more field/value set(s)
Insert a new record into database table, prepare the sql statement. All values to be changed are stored in ap list. Sub-in the values to the prepared statement and execute it.

Return values:
number of rows affected
-1 on failure

Definition at line 731 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_copy_string(), ast_log(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, custom_prepare(), LOG_WARNING, RES_ODBC_CONNECTED, and custom_prepare_struct::sql.

00732 {
00733    struct odbc_obj *obj;
00734    SQLHSTMT stmt;
00735    char sql[256];
00736    char keys[256];
00737    char vals[256];
00738    SQLLEN rowcount=0;
00739    const char *newparam;
00740    int res;
00741    va_list aq;
00742    struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
00743    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00744 
00745    if (!table) {
00746       return -1;
00747    }
00748 
00749    obj = ast_odbc_request_obj2(database, connected_flag);
00750    if (!obj) {
00751       return -1;
00752    }
00753 
00754    va_copy(aq, ap);
00755 
00756    newparam = va_arg(aq, const char *);
00757    if (!newparam)  {
00758       va_end(aq);
00759       ast_odbc_release_obj(obj);
00760       return -1;
00761    }
00762    va_arg(aq, const char *);
00763    snprintf(keys, sizeof(keys), "%s", newparam);
00764    ast_copy_string(vals, "?", sizeof(vals));
00765    while ((newparam = va_arg(aq, const char *))) {
00766       snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
00767       snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
00768       va_arg(aq, const char *);
00769    }
00770    va_end(aq);
00771    snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
00772 
00773 
00774    va_copy(cps.ap, ap);
00775    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00776    va_end(cps.ap);
00777 
00778    if (!stmt) {
00779       ast_odbc_release_obj(obj);
00780       return -1;
00781    }
00782 
00783    res = SQLRowCount(stmt, &rowcount);
00784    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00785    ast_odbc_release_obj(obj);
00786 
00787    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00788       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00789       return -1;
00790    }
00791 
00792    if (rowcount >= 0)
00793       return (int)rowcount;
00794 
00795    return -1;
00796 }

static int unload_module ( void   )  [static]

Definition at line 1168 of file res_config_odbc.c.

References ast_config_engine_deregister(), and ast_verb.

01169 {
01170    ast_config_engine_deregister(&odbc_engine);
01171 
01172    ast_verb(1, "res_config_odbc unloaded.\n");
01173    return 0;
01174 }

static int unload_odbc ( const char *  a,
const char *  b 
) [static]

Definition at line 1150 of file res_config_odbc.c.

References ast_odbc_clear_cache().

01151 {
01152    return ast_odbc_clear_cache(a, b);
01153 }

static int update2_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Execute an UPDATE query.

Parameters:
database 
table 
ap list containing one or more field/value set(s).
Update a database table, preparing the sql statement from a list of key/value pairs specified in ap. The lookup pairs are specified first and are separated from the update pairs by a sentinel value. Sub-in the values to the prepared statement and execute it.

Return values:
number of rows affected
-1 on failure

Definition at line 679 of file res_config_odbc.c.

References update2_prepare_struct::ap, ast_log(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj, ast_str_buffer(), ast_str_thread_get(), update2_prepare_struct::database, LOG_WARNING, sql_buf, and update2_prepare().

00680 {
00681    struct odbc_obj *obj;
00682    SQLHSTMT stmt;
00683    struct update2_prepare_struct ups = { .database = database, .table = table, };
00684    struct ast_str *sql;
00685    int res;
00686    SQLLEN rowcount = 0;
00687 
00688    if (!(obj = ast_odbc_request_obj(database, 0))) {
00689       return -1;
00690    }
00691 
00692    va_copy(ups.ap, ap);
00693    if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
00694       va_end(ups.ap);
00695       ast_odbc_release_obj(obj);
00696       return -1;
00697    }
00698    va_end(ups.ap);
00699 
00700    res = SQLRowCount(stmt, &rowcount);
00701    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00702    ast_odbc_release_obj(obj);
00703 
00704    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00705       /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
00706       sql = ast_str_thread_get(&sql_buf, 16);
00707       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
00708       return -1;
00709    }
00710 
00711    if (rowcount >= 0) {
00712       return (int)rowcount;
00713    }
00714 
00715    return -1;
00716 }

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

Definition at line 581 of file res_config_odbc.c.

References update2_prepare_struct::ap, ast_log(), ast_odbc_find_column(), ast_odbc_find_table(), ast_odbc_release_table, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), odbc_obj::con, update2_prepare_struct::database, first, LOG_ERROR, LOG_NOTICE, LOG_WARNING, sql_buf, and update2_prepare_struct::table.

Referenced by update2_odbc().

00582 {
00583    int res, x = 1, first = 1;
00584    struct update2_prepare_struct *ups = data;
00585    const char *newparam, *newval;
00586    struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
00587    SQLHSTMT stmt;
00588    va_list ap;
00589    struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
00590 
00591    if (!sql) {
00592       if (tableptr) {
00593          ast_odbc_release_table(tableptr);
00594       }
00595       return NULL;
00596    }
00597 
00598    if (!tableptr) {
00599       ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'.  Update will fail!\n", ups->table, ups->database);
00600       return NULL;
00601    }
00602 
00603    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00604    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00605       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00606       ast_odbc_release_table(tableptr);
00607       return NULL;
00608    }
00609 
00610    ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
00611 
00612    /* Start by finding the second set of parameters */
00613    va_copy(ap, ups->ap);
00614 
00615    while ((newparam = va_arg(ap, const char *))) {
00616       newval = va_arg(ap, const char *);
00617    }
00618 
00619    while ((newparam = va_arg(ap, const char *))) {
00620       newval = va_arg(ap, const char *);
00621       if (ast_odbc_find_column(tableptr, newparam)) {
00622          ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam);
00623          SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00624          first = 0;
00625       } else {
00626          ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database);
00627       }
00628    }
00629    va_end(ap);
00630 
00631    ast_str_append(&sql, 0, "WHERE");
00632    first = 1;
00633 
00634    /* Restart search, because we need to add the search parameters */
00635    va_copy(ap, ups->ap);
00636 
00637    while ((newparam = va_arg(ap, const char *))) {
00638       newval = va_arg(ap, const char *);
00639       if (!ast_odbc_find_column(tableptr, newparam)) {
00640          va_end(ap);
00641          ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", newparam, ups->table, ups->database);
00642          ast_odbc_release_table(tableptr);
00643          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00644          return NULL;
00645       }
00646       ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam);
00647       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00648       first = 0;
00649    }
00650    va_end(ap);
00651 
00652    /* Done with the table metadata */
00653    ast_odbc_release_table(tableptr);
00654 
00655    res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
00656    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00657       ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
00658       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00659       return NULL;
00660    }
00661 
00662    return stmt;
00663 }

static int update_odbc ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
va_list  ap 
) [static]

Excute an UPDATE query.

Parameters:
database 
table 
keyfield where clause field
lookup value of field for where clause
ap list containing one or more field/value set(s).
Update a database table, prepare the sql statement using keyfield and lookup control the number of records to change. All values to be changed are stored in ap list. Sub-in the values to the prepared statement and execute it.

Return values:
number of rows affected
-1 on failure

Definition at line 481 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_log(), ast_odbc_find_column(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_release_table, ast_odbc_request_obj2, ast_string_field_free_memory, ast_string_field_init, ast_strlen_zero(), custom_prepare(), LOG_WARNING, odbc_cache_columns::nullable, RES_ODBC_CONNECTED, custom_prepare_struct::skip, custom_prepare_struct::sql, and odbc_cache_columns::type.

00482 {
00483    struct odbc_obj *obj;
00484    SQLHSTMT stmt;
00485    char sql[256];
00486    SQLLEN rowcount=0;
00487    const char *newparam;
00488    int res, count = 1;
00489    va_list aq;
00490    struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00491    struct odbc_cache_tables *tableptr;
00492    struct odbc_cache_columns *column = NULL;
00493    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00494 
00495    if (!table) {
00496       return -1;
00497    }
00498 
00499    if (ast_string_field_init(&cps, 256)) {
00500       return -1;
00501    }
00502 
00503    tableptr = ast_odbc_find_table(database, table);
00504    if (!(obj = ast_odbc_request_obj2(database, connected_flag))) {
00505       ast_odbc_release_table(tableptr);
00506       ast_string_field_free_memory(&cps);
00507       return -1;
00508    }
00509 
00510    va_copy(aq, ap);
00511    newparam = va_arg(aq, const char *);
00512    if (!newparam)  {
00513       va_end(aq);
00514       ast_odbc_release_obj(obj);
00515       ast_odbc_release_table(tableptr);
00516       ast_string_field_free_memory(&cps);
00517       return -1;
00518    }
00519    va_arg(aq, const char *);
00520 
00521    if (tableptr && !ast_odbc_find_column(tableptr, newparam)) {
00522       ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", newparam, table, database);
00523    }
00524 
00525    snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
00526    while((newparam = va_arg(aq, const char *))) {
00527       va_arg(aq, const char *);
00528       if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count > 63) {
00529          /* NULL test for integer-based columns */
00530          if (ast_strlen_zero(newparam) && tableptr && column && column->nullable && count < 64 &&
00531             (column->type == SQL_INTEGER || column->type == SQL_BIGINT ||
00532              column->type == SQL_SMALLINT || column->type == SQL_TINYINT ||
00533              column->type == SQL_NUMERIC || column->type == SQL_DECIMAL)) {
00534             snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=NULL", newparam);
00535             cps.skip |= (1LL << count);
00536          } else {
00537             snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
00538          }
00539       } else { /* the column does not exist in the table */
00540          cps.skip |= (1LL << count);
00541       }
00542       count++;
00543    }
00544    va_end(aq);
00545    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
00546    ast_odbc_release_table(tableptr);
00547 
00548    va_copy(cps.ap, ap);
00549    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00550    va_end(cps.ap);
00551 
00552    if (!stmt) {
00553       ast_odbc_release_obj(obj);
00554       ast_string_field_free_memory(&cps);
00555       return -1;
00556    }
00557 
00558    res = SQLRowCount(stmt, &rowcount);
00559    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00560    ast_odbc_release_obj(obj);
00561    ast_string_field_free_memory(&cps);
00562 
00563    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00564       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00565       return -1;
00566    }
00567 
00568    if (rowcount >= 0) {
00569       return (int) rowcount;
00570    }
00571 
00572    return -1;
00573 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime ODBC configuration" , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, } [static]

Definition at line 1193 of file res_config_odbc.c.

Definition at line 1193 of file res_config_odbc.c.

struct ast_config_engine odbc_engine [static]

Definition at line 1155 of file res_config_odbc.c.

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

Definition at line 50 of file res_config_odbc.c.


Generated on Thu Oct 11 06:37:02 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6