Mon Aug 31 12:30:43 2015

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"

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 ENCODE_CHUNK(buffer, s)
#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_rowdata_buf (void)
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 is_text (const struct odbc_cache_columns *column)
static SQLHSTMT length_determination_odbc_prepare (struct odbc_obj *obj, void *data)
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 = "ac1f6a56484a8820659555499174e588" , .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 rowdata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_rowdata_buf , .custom_init = NULL , }
static struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }

Detailed Description

odbc+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 ENCODE_CHUNK ( buffer,
 ) 

Definition at line 63 of file res_config_odbc.c.

Referenced by custom_prepare().

#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 1099 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 1100 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_rowdata_buf ( void   )  [static]

Definition at line 51 of file res_config_odbc.c.

00053 {

static void __init_sql_buf ( void   )  [static]

Definition at line 50 of file res_config_odbc.c.

00053 {

static void __reg_module ( void   )  [static]

Definition at line 1302 of file res_config_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 1302 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 962 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_free, ast_log(), ast_malloc, 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, length_determination_odbc_prepare(), LOG_NOTICE, LOG_WARNING, RES_ODBC_CONNECTED, config_odbc_obj::sql, config_odbc_obj::var_name, config_odbc_obj::var_val, and config_odbc_obj::var_val_size.

00963 {
00964    struct ast_variable *new_v;
00965    struct ast_category *cur_cat;
00966    int res = 0;
00967    struct odbc_obj *obj;
00968    char sqlbuf[1024] = "";
00969    char *sql = sqlbuf;
00970    size_t sqlleft = sizeof(sqlbuf);
00971    unsigned int last_cat_metric = 0;
00972    SQLSMALLINT rowcount = 0;
00973    SQLHSTMT stmt;
00974    char last[128] = "";
00975    struct config_odbc_obj q;
00976    struct ast_flags loader_flags = { 0 };
00977    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00978 
00979    memset(&q, 0, sizeof(q));
00980 
00981    if (!file || !strcmp (file, "res_config_odbc.conf"))
00982       return NULL;      /* cant configure myself with myself ! */
00983 
00984    obj = ast_odbc_request_obj2(database, connected_flag);
00985    if (!obj)
00986       return NULL;
00987 
00988    q.sql = sqlbuf;
00989 
00990    ast_build_string(&sql, &sqlleft, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", table, file);
00991 
00992    stmt = ast_odbc_prepare_and_execute(obj, length_determination_odbc_prepare, &q);
00993 
00994    if (!stmt) {
00995       ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
00996       ast_odbc_release_obj(obj);
00997       return NULL;
00998    }
00999 
01000    res = SQLNumResultCols(stmt, &rowcount);
01001 
01002    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01003       ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
01004       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01005       ast_odbc_release_obj(obj);
01006       return NULL;
01007    }
01008 
01009    if (!rowcount) {
01010       ast_log(LOG_NOTICE, "found nothing\n");
01011       ast_odbc_release_obj(obj);
01012       return cfg;
01013    }
01014 
01015    /* There will be only one result for this, the maximum length of a variable value */
01016    if (SQLFetch(stmt) == SQL_NO_DATA) {
01017       ast_log(LOG_NOTICE, "Failed to determine maximum length of a configuration value\n");
01018       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01019       ast_odbc_release_obj(obj);
01020       return NULL;
01021    }
01022 
01023    /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
01024    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01025    sql = sqlbuf;
01026    sqlleft = sizeof(sqlbuf);
01027 
01028    ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
01029    ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
01030    ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
01031 
01032    q.var_val_size += 1;
01033    q.var_val = ast_malloc(q.var_val_size);
01034    if (!q.var_val) {
01035       ast_log(LOG_WARNING, "Could not create buffer for reading in configuration values for '%s'\n", file);
01036       ast_odbc_release_obj(obj);
01037       return NULL;
01038    }
01039 
01040    stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
01041 
01042    if (!stmt) {
01043       ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
01044       ast_odbc_release_obj(obj);
01045       ast_free(q.var_val);
01046       return NULL;
01047    }
01048 
01049    res = SQLNumResultCols(stmt, &rowcount);
01050 
01051    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01052       ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
01053       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01054       ast_odbc_release_obj(obj);
01055       ast_free(q.var_val);
01056       return NULL;
01057    }
01058 
01059    if (!rowcount) {
01060       ast_log(LOG_NOTICE, "found nothing\n");
01061       ast_odbc_release_obj(obj);
01062       ast_free(q.var_val);
01063       return cfg;
01064    }
01065 
01066    cur_cat = ast_config_get_current_category(cfg);
01067 
01068    while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
01069       if (!strcmp (q.var_name, "#include")) {
01070          if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
01071             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01072             ast_odbc_release_obj(obj);
01073             ast_free(q.var_val);
01074             return NULL;
01075          }
01076          continue;
01077       } 
01078       if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
01079          cur_cat = ast_category_new(q.category, "", 99999);
01080          if (!cur_cat) {
01081             ast_log(LOG_WARNING, "Out of memory!\n");
01082             break;
01083          }
01084          strcpy(last, q.category);
01085          last_cat_metric   = q.cat_metric;
01086          ast_category_append(cfg, cur_cat);
01087       }
01088 
01089       new_v = ast_variable_new(q.var_name, q.var_val, "");
01090       ast_variable_append(cur_cat, new_v);
01091    }
01092 
01093    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
01094    ast_odbc_release_obj(obj);
01095    ast_free(q.var_val);
01096    return cfg;
01097 }

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

Definition at line 935 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, config_odbc_obj::var_val, and config_odbc_obj::var_val_size.

Referenced by config_odbc().

00936 {
00937    struct config_odbc_obj *q = data;
00938    SQLHSTMT sth;
00939    int res;
00940 
00941    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00942    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00943       ast_verb(4, "Failure in AllocStatement %d\n", res);
00944       return NULL;
00945    }
00946 
00947    res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00948    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00949       ast_verb(4, "Error in PREPARE %d\n", res);
00950       SQLFreeHandle(SQL_HANDLE_STMT, sth);
00951       return NULL;
00952    }
00953 
00954    SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
00955    SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
00956    SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
00957    SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err);
00958 
00959    return sth;
00960 }

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

Definition at line 99 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, ENCODE_CHUNK, 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().

00100 {
00101    int res, x = 1, count = 0;
00102    struct custom_prepare_struct *cps = data;
00103    const char *newparam, *newval;
00104    char encodebuf[1024];
00105    SQLHSTMT stmt;
00106    va_list ap;
00107 
00108    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00109    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00110       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00111       return NULL;
00112    }
00113 
00114    ast_debug(1, "Skip: %llu; SQL: %s\n", cps->skip, cps->sql);
00115 
00116    res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
00117    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00118       ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
00119       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00120       return NULL;
00121    }
00122 
00123    va_copy(ap, cps->ap);
00124    while ((newparam = va_arg(ap, const char *))) {
00125       newval = va_arg(ap, const char *);
00126       if ((1LL << count++) & cps->skip) {
00127          ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1ULL << (count - 1), cps->skip);
00128          continue;
00129       }
00130       ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, newparam, newval);
00131       if (strchr(newval, ';') || strchr(newval, '^')) {
00132          ENCODE_CHUNK(encodebuf, newval);
00133          ast_string_field_set(cps, encoding[x], encodebuf);
00134          newval = cps->encoding[x];
00135       }
00136       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00137    }
00138    va_end(ap);
00139 
00140    if (!ast_strlen_zero(cps->extra)) {
00141       const char *newval = cps->extra;
00142       if (strchr(newval, ';') || strchr(newval, '^')) {
00143          ENCODE_CHUNK(encodebuf, newval);
00144          ast_string_field_set(cps, encoding[x], encodebuf);
00145          newval = cps->encoding[x];
00146       } 
00147       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00148    }
00149 
00150    return stmt;
00151 }

static void decode_chunk ( char *  chunk  )  [static]

Definition at line 83 of file res_config_odbc.c.

Referenced by realtime_multi_odbc(), and realtime_odbc().

00084 {
00085    for (; *chunk; chunk++) {
00086       if (*chunk == '^' && strchr("0123456789ABCDEF", chunk[1]) && strchr("0123456789ABCDEF", chunk[2])) {
00087          sscanf(chunk + 1, "%02hhX", (unsigned char *)chunk);
00088          memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
00089       }
00090    }
00091 }

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 840 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, ast_string_field_free_memory, ast_string_field_init, custom_prepare(), LOG_WARNING, RES_ODBC_CONNECTED, and custom_prepare_struct::sql.

00841 {
00842    struct odbc_obj *obj;
00843    SQLHSTMT stmt;
00844    char sql[256];
00845    SQLLEN rowcount=0;
00846    const char *newparam;
00847    int res;
00848    va_list aq;
00849    struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00850    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00851 
00852    if (!table) {
00853       return -1;
00854    }
00855 
00856    obj = ast_odbc_request_obj2(database, connected_flag);
00857    if (!obj) {
00858       return -1;
00859    }
00860 
00861    snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
00862 
00863    va_copy(aq, ap);
00864    while((newparam = va_arg(aq, const char *))) {
00865       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
00866       va_arg(aq, const char *);
00867    }
00868    va_end(aq);
00869    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
00870 
00871    if (ast_string_field_init(&cps, 256)) {
00872       ast_odbc_release_obj(obj);
00873       return -1;
00874    }
00875    va_copy(cps.ap, ap);
00876    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00877    va_end(cps.ap);
00878    ast_string_field_free_memory(&cps);
00879 
00880    if (!stmt) {
00881       ast_odbc_release_obj(obj);
00882       return -1;
00883    }
00884 
00885    res = SQLRowCount(stmt, &rowcount);
00886    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00887    ast_odbc_release_obj(obj);
00888 
00889    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00890       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00891       return -1;
00892    }
00893 
00894    if (rowcount >= 0)
00895       return (int)rowcount;
00896 
00897    return -1;
00898 }

static int is_text ( const struct odbc_cache_columns column  )  [inline, static]

Definition at line 93 of file res_config_odbc.c.

References odbc_cache_columns::type.

Referenced by update_odbc().

00094 {
00095    return column->type == SQL_CHAR || column->type == SQL_VARCHAR || column->type == SQL_LONGVARCHAR
00096       || column->type == SQL_WCHAR || column->type == SQL_WVARCHAR || column->type == SQL_WLONGVARCHAR;
00097 }

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

Definition at line 911 of file res_config_odbc.c.

References ast_verb, odbc_obj::con, config_odbc_obj::err, config_odbc_obj::sql, and config_odbc_obj::var_val_size.

Referenced by config_odbc().

00912 {
00913    struct config_odbc_obj *q = data;
00914    SQLHSTMT sth;
00915    int res;
00916 
00917    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00918    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00919       ast_verb(4, "Failure in AllocStatement %d\n", res);
00920       return NULL;
00921    }
00922 
00923    res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00924    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00925       ast_verb(4, "Error in PREPARE %d\n", res);
00926       SQLFreeHandle(SQL_HANDLE_STMT, sth);
00927       return NULL;
00928    }
00929 
00930    SQLBindCol(sth, 1, SQL_C_ULONG, &q->var_val_size, sizeof(q->var_val_size), &q->err);
00931 
00932    return sth;
00933 }

static int load_module ( void   )  [static]

Definition at line 1285 of file res_config_odbc.c.

References ast_config_engine_register(), and ast_verb.

01286 {
01287    ast_config_engine_register(&odbc_engine);
01288    ast_verb(1, "res_config_odbc loaded.\n");
01289    return 0;
01290 }

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 335 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_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_size(), ast_str_strlen(), ast_str_thread_get(), ast_str_update(), 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, rowdata_buf, custom_prepare_struct::sql, and var.

00336 {
00337    struct odbc_obj *obj;
00338    SQLHSTMT stmt;
00339    char sql[1024];
00340    char coltitle[256];
00341    struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
00342    const char *initfield;
00343    char *op;
00344    const char *newparam;
00345    char *stringp;
00346    char *chunk;
00347    SQLSMALLINT collen;
00348    int res;
00349    int x;
00350    struct ast_variable *var=NULL;
00351    struct ast_config *cfg=NULL;
00352    struct ast_category *cat=NULL;
00353    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00354    SQLULEN colsize;
00355    SQLSMALLINT colcount=0;
00356    SQLSMALLINT datatype;
00357    SQLSMALLINT decimaldigits;
00358    SQLSMALLINT nullable;
00359    SQLLEN indicator;
00360    struct custom_prepare_struct cps = { .sql = sql };
00361    va_list aq;
00362 
00363    if (!table) {
00364       return NULL;
00365    }
00366 
00367    obj = ast_odbc_request_obj2(database, connected_flag);
00368    if (!obj) {
00369       return NULL;
00370    }
00371 
00372    va_copy(aq, ap);
00373    newparam = va_arg(aq, const char *);
00374    if (!newparam)  {
00375       va_end(aq);
00376       ast_odbc_release_obj(obj);
00377       return NULL;
00378    }
00379 
00380    initfield = ast_strdupa(newparam);
00381    if ((op = strchr(initfield, ' '))) {
00382       *op = '\0';
00383    }
00384 
00385    va_arg(aq, const char *);
00386    op = !strchr(newparam, ' ') ? " =" : "";
00387    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
00388       strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00389    while((newparam = va_arg(aq, const char *))) {
00390       op = !strchr(newparam, ' ') ? " =" : "";
00391       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
00392          strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00393       va_arg(aq, const char *);
00394    }
00395    va_end(aq);
00396 
00397    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00398 
00399    if (ast_string_field_init(&cps, 256)) {
00400       ast_odbc_release_obj(obj);
00401       return NULL;
00402    }
00403    va_copy(cps.ap, ap);
00404    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00405    va_end(cps.ap);
00406    ast_string_field_free_memory(&cps);
00407 
00408    if (!stmt) {
00409       ast_odbc_release_obj(obj);
00410       return NULL;
00411    }
00412 
00413    res = SQLNumResultCols(stmt, &colcount);
00414    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00415       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00416       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00417       ast_odbc_release_obj(obj);
00418       return NULL;
00419    }
00420 
00421    cfg = ast_config_new();
00422    if (!cfg) {
00423       ast_log(LOG_WARNING, "Out of memory!\n");
00424       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00425       ast_odbc_release_obj(obj);
00426       return NULL;
00427    }
00428 
00429    while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
00430       var = NULL;
00431       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00432          ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00433          continue;
00434       }
00435       cat = ast_category_new("","",99999);
00436       if (!cat) {
00437          ast_log(LOG_WARNING, "Out of memory!\n");
00438          continue;
00439       }
00440       for (x=0;x<colcount;x++) {
00441          colsize = 0;
00442          collen = sizeof(coltitle);
00443          res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
00444                   &datatype, &colsize, &decimaldigits, &nullable);
00445          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00446             ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00447             ast_category_destroy(cat);
00448             goto next_sql_fetch;
00449          }
00450 
00451          ast_str_reset(rowdata);
00452          indicator = 0;
00453 
00454          res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
00455          ast_str_update(rowdata);
00456          if (indicator == SQL_NULL_DATA) {
00457             continue;
00458          }
00459 
00460          if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
00461             if (indicator != ast_str_strlen(rowdata)) {
00462                /* If the available space was not enough to contain the row data enlarge and read in the rest */
00463                ast_str_make_space(&rowdata, indicator + 1);
00464                res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
00465                   ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
00466                ast_str_update(rowdata);
00467             }
00468          }
00469 
00470          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00471             ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00472             ast_category_destroy(cat);
00473             goto next_sql_fetch;
00474          }
00475          stringp = ast_str_buffer(rowdata);
00476          while (stringp) {
00477             chunk = strsep(&stringp, ";");
00478             if (!ast_strlen_zero(ast_strip(chunk))) {
00479                if (strchr(chunk, '^')) {
00480                   decode_chunk(chunk);
00481                }
00482                if (!strcmp(initfield, coltitle)) {
00483                   ast_category_rename(cat, chunk);
00484                }
00485                var = ast_variable_new(coltitle, chunk, "");
00486                ast_variable_append(cat, var);
00487             }
00488          }
00489       }
00490       ast_category_append(cfg, cat);
00491 next_sql_fetch:;
00492    }
00493 
00494    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00495    ast_odbc_release_obj(obj);
00496    return cfg;
00497 }

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 166 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_log(), ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_set(), ast_str_size(), ast_str_strlen(), ast_str_thread_get(), ast_str_update(), 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, rowdata_buf, custom_prepare_struct::sql, and var.

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

static int reload_module ( void   )  [static]

Definition at line 1292 of file res_config_odbc.c.

01293 {
01294    return 0;
01295 }

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

Definition at line 1102 of file res_config_odbc.c.

References ast_log(), ast_odbc_find_table(), 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.

01103 {
01104    struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
01105    struct odbc_cache_columns *col;
01106    char *elm;
01107    int type, size;
01108 
01109    if (!tableptr) {
01110       return -1;
01111    }
01112 
01113    while ((elm = va_arg(ap, char *))) {
01114       type = va_arg(ap, require_type);
01115       size = va_arg(ap, int);
01116       /* Check if the field matches the criteria */
01117       AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
01118          if (strcmp(col->name, elm) == 0) {
01119             /* Type check, first.  Some fields are more particular than others */
01120             switch (col->type) {
01121             case SQL_CHAR:
01122             case SQL_VARCHAR:
01123             case SQL_LONGVARCHAR:
01124 #ifdef HAVE_ODBC_WCHAR
01125             case SQL_WCHAR:
01126             case SQL_WVARCHAR:
01127             case SQL_WLONGVARCHAR:
01128 #endif
01129             case SQL_BINARY:
01130             case SQL_VARBINARY:
01131             case SQL_LONGVARBINARY:
01132             case SQL_GUID:
01133 #define CHECK_SIZE(n) \
01134                   if (col->size < n) {      \
01135                      warn_length(col, n);  \
01136                   }                         \
01137                   break;
01138                switch (type) {
01139                case RQ_UINTEGER1: CHECK_SIZE(3)  /*         255 */
01140                case RQ_INTEGER1:  CHECK_SIZE(4)  /*        -128 */
01141                case RQ_UINTEGER2: CHECK_SIZE(5)  /*       65535 */
01142                case RQ_INTEGER2:  CHECK_SIZE(6)  /*      -32768 */
01143                case RQ_UINTEGER3:                /*    16777215 */
01144                case RQ_INTEGER3:  CHECK_SIZE(8)  /*    -8388608 */
01145                case RQ_DATE:                     /*  2008-06-09 */
01146                case RQ_UINTEGER4: CHECK_SIZE(10) /*  4200000000 */
01147                case RQ_INTEGER4:  CHECK_SIZE(11) /* -2100000000 */
01148                case RQ_DATETIME:                 /* 2008-06-09 16:03:47 */
01149                case RQ_UINTEGER8: CHECK_SIZE(19) /* trust me    */
01150                case RQ_INTEGER8:  CHECK_SIZE(20) /* ditto       */
01151                case RQ_FLOAT:
01152                case RQ_CHAR:      CHECK_SIZE(size)
01153                }
01154 #undef CHECK_SIZE
01155                break;
01156             case SQL_TYPE_DATE:
01157                if (type != RQ_DATE) {
01158                   warn_type(col, type);
01159                }
01160                break;
01161             case SQL_TYPE_TIMESTAMP:
01162             case SQL_TIMESTAMP:
01163                if (type != RQ_DATE && type != RQ_DATETIME) {
01164                   warn_type(col, type);
01165                }
01166                break;
01167             case SQL_BIT:
01168                warn_length(col, size);
01169                break;
01170 #define WARN_TYPE_OR_LENGTH(n)   \
01171                   if (!ast_rq_is_int(type)) {  \
01172                      warn_type(col, type);    \
01173                   } else {                     \
01174                      warn_length(col, n);  \
01175                   }
01176             case SQL_TINYINT:
01177                if (type != RQ_UINTEGER1) {
01178                   WARN_TYPE_OR_LENGTH(size)
01179                }
01180                break;
01181             case SQL_C_STINYINT:
01182                if (type != RQ_INTEGER1) {
01183                   WARN_TYPE_OR_LENGTH(size)
01184                }
01185                break;
01186             case SQL_C_USHORT:
01187                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
01188                   WARN_TYPE_OR_LENGTH(size)
01189                }
01190                break;
01191             case SQL_SMALLINT:
01192             case SQL_C_SSHORT:
01193                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
01194                   WARN_TYPE_OR_LENGTH(size)
01195                }
01196                break;
01197             case SQL_C_ULONG:
01198                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01199                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01200                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01201                   type != RQ_INTEGER4) {
01202                   WARN_TYPE_OR_LENGTH(size)
01203                }
01204                break;
01205             case SQL_INTEGER:
01206             case SQL_C_SLONG:
01207                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01208                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01209                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01210                   type != RQ_INTEGER4) {
01211                   WARN_TYPE_OR_LENGTH(size)
01212                }
01213                break;
01214             case SQL_C_UBIGINT:
01215                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01216                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01217                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01218                   type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
01219                   type != RQ_INTEGER8) {
01220                   WARN_TYPE_OR_LENGTH(size)
01221                }
01222                break;
01223             case SQL_BIGINT:
01224             case SQL_C_SBIGINT:
01225                if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01226                   type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01227                   type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01228                   type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
01229                   type != RQ_INTEGER8) {
01230                   WARN_TYPE_OR_LENGTH(size)
01231                }
01232                break;
01233 #undef WARN_TYPE_OR_LENGTH
01234             case SQL_NUMERIC:
01235             case SQL_DECIMAL:
01236             case SQL_FLOAT:
01237             case SQL_REAL:
01238             case SQL_DOUBLE:
01239                if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
01240                   warn_type(col, type);
01241                }
01242                break;
01243             default:
01244                ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm);
01245             }
01246             break;
01247          }
01248       }
01249       if (!col) {
01250          ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
01251       }
01252    }
01253    AST_RWLIST_UNLOCK(&tableptr->columns);
01254    return 0;
01255 }

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 754 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, ast_string_field_free_memory, ast_string_field_init, custom_prepare(), LOG_WARNING, RES_ODBC_CONNECTED, and custom_prepare_struct::sql.

00755 {
00756    struct odbc_obj *obj;
00757    SQLHSTMT stmt;
00758    char sql[256];
00759    char keys[256];
00760    char vals[256];
00761    SQLLEN rowcount=0;
00762    const char *newparam;
00763    int res;
00764    va_list aq;
00765    struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
00766    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00767 
00768    if (!table) {
00769       return -1;
00770    }
00771 
00772    obj = ast_odbc_request_obj2(database, connected_flag);
00773    if (!obj) {
00774       return -1;
00775    }
00776 
00777    va_copy(aq, ap);
00778 
00779    newparam = va_arg(aq, const char *);
00780    if (!newparam)  {
00781       va_end(aq);
00782       ast_odbc_release_obj(obj);
00783       return -1;
00784    }
00785    va_arg(aq, const char *);
00786    snprintf(keys, sizeof(keys), "%s", newparam);
00787    ast_copy_string(vals, "?", sizeof(vals));
00788    while ((newparam = va_arg(aq, const char *))) {
00789       snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
00790       snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
00791       va_arg(aq, const char *);
00792    }
00793    va_end(aq);
00794    snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
00795 
00796    if (ast_string_field_init(&cps, 256)) {
00797       ast_odbc_release_obj(obj);
00798       return -1;
00799    }
00800    va_copy(cps.ap, ap);
00801    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00802    va_end(cps.ap);
00803    ast_string_field_free_memory(&cps);
00804 
00805    if (!stmt) {
00806       ast_odbc_release_obj(obj);
00807       return -1;
00808    }
00809 
00810    res = SQLRowCount(stmt, &rowcount);
00811    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00812    ast_odbc_release_obj(obj);
00813 
00814    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00815       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00816       return -1;
00817    }
00818 
00819    if (rowcount >= 0)
00820       return (int)rowcount;
00821 
00822    return -1;
00823 }

static int unload_module ( void   )  [static]

Definition at line 1277 of file res_config_odbc.c.

References ast_config_engine_deregister(), and ast_verb.

01278 {
01279    ast_config_engine_deregister(&odbc_engine);
01280 
01281    ast_verb(1, "res_config_odbc unloaded.\n");
01282    return 0;
01283 }

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

Definition at line 1259 of file res_config_odbc.c.

References ast_odbc_clear_cache().

01260 {
01261    return ast_odbc_clear_cache(a, b);
01262 }

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 702 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().

00703 {
00704    struct odbc_obj *obj;
00705    SQLHSTMT stmt;
00706    struct update2_prepare_struct ups = { .database = database, .table = table, };
00707    struct ast_str *sql;
00708    int res;
00709    SQLLEN rowcount = 0;
00710 
00711    if (!(obj = ast_odbc_request_obj(database, 0))) {
00712       return -1;
00713    }
00714 
00715    va_copy(ups.ap, ap);
00716    if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
00717       va_end(ups.ap);
00718       ast_odbc_release_obj(obj);
00719       return -1;
00720    }
00721    va_end(ups.ap);
00722 
00723    res = SQLRowCount(stmt, &rowcount);
00724    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00725    ast_odbc_release_obj(obj);
00726 
00727    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00728       /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
00729       sql = ast_str_thread_get(&sql_buf, 16);
00730       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
00731       return -1;
00732    }
00733 
00734    if (rowcount >= 0) {
00735       return (int)rowcount;
00736    }
00737 
00738    return -1;
00739 }

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

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

00605 {
00606    int res, x = 1, first = 1;
00607    struct update2_prepare_struct *ups = data;
00608    const char *newparam, *newval;
00609    struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
00610    SQLHSTMT stmt;
00611    va_list ap;
00612    struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
00613 
00614    if (!sql) {
00615       if (tableptr) {
00616          ast_odbc_release_table(tableptr);
00617       }
00618       return NULL;
00619    }
00620 
00621    if (!tableptr) {
00622       ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'.  Update will fail!\n", ups->table, ups->database);
00623       return NULL;
00624    }
00625 
00626    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00627    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00628       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00629       ast_odbc_release_table(tableptr);
00630       return NULL;
00631    }
00632 
00633    ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
00634 
00635    /* Start by finding the second set of parameters */
00636    va_copy(ap, ups->ap);
00637 
00638    while ((newparam = va_arg(ap, const char *))) {
00639       newval = va_arg(ap, const char *);
00640    }
00641 
00642    while ((newparam = va_arg(ap, const char *))) {
00643       newval = va_arg(ap, const char *);
00644       if (ast_odbc_find_column(tableptr, newparam)) {
00645          ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam);
00646          SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00647          first = 0;
00648       } else {
00649          ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database);
00650       }
00651    }
00652    va_end(ap);
00653 
00654    ast_str_append(&sql, 0, "WHERE");
00655    first = 1;
00656 
00657    /* Restart search, because we need to add the search parameters */
00658    va_copy(ap, ups->ap);
00659 
00660    while ((newparam = va_arg(ap, const char *))) {
00661       newval = va_arg(ap, const char *);
00662       if (!ast_odbc_find_column(tableptr, newparam)) {
00663          va_end(ap);
00664          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);
00665          ast_odbc_release_table(tableptr);
00666          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00667          return NULL;
00668       }
00669       ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam);
00670       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00671       first = 0;
00672    }
00673    va_end(ap);
00674 
00675    /* Done with the table metadata */
00676    ast_odbc_release_table(tableptr);
00677 
00678    res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
00679    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00680       ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
00681       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00682       return NULL;
00683    }
00684 
00685    return stmt;
00686 }

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 514 of file res_config_odbc.c.

References custom_prepare_struct::ap, ast_log(), ast_odbc_allow_empty_string_in_nontext(), 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(), is_text(), LOG_WARNING, odbc_cache_columns::nullable, RES_ODBC_CONNECTED, custom_prepare_struct::skip, and custom_prepare_struct::sql.

00515 {
00516    struct odbc_obj *obj;
00517    SQLHSTMT stmt;
00518    char sql[256];
00519    SQLLEN rowcount=0;
00520    const char *newparam, *newval;
00521    int res, count = 0, paramcount = 0;
00522    va_list aq;
00523    struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00524    struct odbc_cache_tables *tableptr;
00525    struct odbc_cache_columns *column = NULL;
00526    struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
00527 
00528    if (!table || !keyfield) {
00529       return -1;
00530    }
00531 
00532    tableptr = ast_odbc_find_table(database, table);
00533    if (!(obj = ast_odbc_request_obj2(database, connected_flag))) {
00534       ast_odbc_release_table(tableptr);
00535       return -1;
00536    }
00537 
00538    if (tableptr && !ast_odbc_find_column(tableptr, keyfield)) {
00539       ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", keyfield, table, database);
00540    }
00541 
00542    va_copy(aq, ap);
00543 
00544    snprintf(sql, sizeof(sql), "UPDATE %s SET ", table);
00545    while((newparam = va_arg(aq, const char *))) {
00546       newval = va_arg(aq, const char *);
00547       if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count >= 64) {
00548          if (paramcount++) {
00549             snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", ");
00550          }
00551          /* NULL test for non-text columns */
00552          if (count < 64 && ast_strlen_zero(newval) && column->nullable && !is_text(column) && !ast_odbc_allow_empty_string_in_nontext(obj)) {
00553             snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", newparam);
00554             cps.skip |= (1LL << count);
00555          } else {
00556             /* Value is not an empty string, or column accepts empty strings, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
00557             snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", newparam);
00558          }
00559       } else { /* the column does not exist in the table */
00560          cps.skip |= (1LL << count);
00561       }
00562       ++count;
00563    }
00564    va_end(aq);
00565    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
00566    ast_odbc_release_table(tableptr);
00567 
00568    if (ast_string_field_init(&cps, 256)) {
00569       ast_odbc_release_obj(obj);
00570       return -1;
00571    }
00572    va_copy(cps.ap, ap);
00573    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00574    va_end(cps.ap);
00575    ast_string_field_free_memory(&cps);
00576 
00577    if (!stmt) {
00578       ast_odbc_release_obj(obj);
00579       return -1;
00580    }
00581 
00582    res = SQLRowCount(stmt, &rowcount);
00583    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00584    ast_odbc_release_obj(obj);
00585 
00586    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00587       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00588       return -1;
00589    }
00590 
00591    if (rowcount >= 0) {
00592       return (int) rowcount;
00593    }
00594 
00595    return -1;
00596 }


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

Definition at line 1302 of file res_config_odbc.c.

Definition at line 1302 of file res_config_odbc.c.

struct ast_config_engine odbc_engine [static]

Definition at line 1264 of file res_config_odbc.c.

struct ast_threadstorage rowdata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_rowdata_buf , .custom_init = NULL , } [static]

Definition at line 51 of file res_config_odbc.c.

Referenced by realtime_multi_odbc(), and realtime_odbc().

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

Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1