Mon Mar 12 2012 21:44:17

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 (   n)
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 973 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 974 of file res_config_odbc.c.

Referenced by require_odbc().

#define WARN_TYPE_OR_LENGTH (   n)
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.

{
static void __reg_module ( void  ) [static]

Definition at line 1177 of file res_config_odbc.c.

static void __unreg_module ( void  ) [static]

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

{
   struct ast_variable *new_v;
   struct ast_category *cur_cat;
   int res = 0;
   struct odbc_obj *obj;
   char sqlbuf[1024] = "";
   char *sql = sqlbuf;
   size_t sqlleft = sizeof(sqlbuf);
   unsigned int last_cat_metric = 0;
   SQLSMALLINT rowcount = 0;
   SQLHSTMT stmt;
   char last[128] = "";
   struct config_odbc_obj q;
   struct ast_flags loader_flags = { 0 };
   struct ast_flags connected_flag = { RES_ODBC_CONNECTED };

   memset(&q, 0, sizeof(q));

   if (!file || !strcmp (file, "res_config_odbc.conf"))
      return NULL;      /* cant configure myself with myself ! */

   obj = ast_odbc_request_obj2(database, connected_flag);
   if (!obj)
      return NULL;

   ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
   ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
   ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
   q.sql = sqlbuf;

   stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);

   if (!stmt) {
      ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
      ast_odbc_release_obj(obj);
      return NULL;
   }

   res = SQLNumResultCols(stmt, &rowcount);

   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
      SQLFreeHandle(SQL_HANDLE_STMT, stmt);
      ast_odbc_release_obj(obj);
      return NULL;
   }

   if (!rowcount) {
      ast_log(LOG_NOTICE, "found nothing\n");
      ast_odbc_release_obj(obj);
      return cfg;
   }

   cur_cat = ast_config_get_current_category(cfg);

   while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
      if (!strcmp (q.var_name, "#include")) {
         if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
            SQLFreeHandle(SQL_HANDLE_STMT, stmt);
            ast_odbc_release_obj(obj);
            return NULL;
         }
         continue;
      } 
      if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
         cur_cat = ast_category_new(q.category, "", 99999);
         if (!cur_cat) {
            ast_log(LOG_WARNING, "Out of memory!\n");
            break;
         }
         strcpy(last, q.category);
         last_cat_metric   = q.cat_metric;
         ast_category_append(cfg, cur_cat);
      }

      new_v = ast_variable_new(q.var_name, q.var_val, "");
      ast_variable_append(cur_cat, new_v);
   }

   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
   ast_odbc_release_obj(obj);
   return cfg;
}
static SQLHSTMT config_odbc_prepare ( struct odbc_obj obj,
void *  data 
) [static]

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

{
   struct config_odbc_obj *q = data;
   SQLHSTMT sth;
   int res;

   res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_verb(4, "Failure in AllocStatement %d\n", res);
      return NULL;
   }

   res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_verb(4, "Error in PREPARE %d\n", res);
      SQLFreeHandle(SQL_HANDLE_STMT, sth);
      return NULL;
   }

   SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
   SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
   SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
   SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);

   return sth;
}
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, encoding, custom_prepare_struct::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().

{
   int res, x = 1, count = 0;
   struct custom_prepare_struct *cps = data;
   const char *newparam, *newval;
   char encodebuf[1024];
   SQLHSTMT stmt;
   va_list ap;

   va_copy(ap, cps->ap);

   res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
      return NULL;
   }

   ast_debug(1, "Skip: %lld; SQL: %s\n", cps->skip, cps->sql);

   res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
      SQLFreeHandle (SQL_HANDLE_STMT, stmt);
      return NULL;
   }

   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
      if ((1LL << count++) & cps->skip) {
         ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1LL << (count - 1), cps->skip);
         continue;
      }
      ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, newparam, newval);
      if (strchr(newval, ';') || strchr(newval, '^')) {
         char *eptr = encodebuf;
         const char *vptr = newval;
         for (; *vptr && eptr < encodebuf + sizeof(encodebuf); vptr++) {
            if (strchr("^;", *vptr)) {
               /* We use ^XX, instead of %XX because '%' is a special character in SQL */
               snprintf(eptr, encodebuf + sizeof(encodebuf) - eptr, "^%02hhX", *vptr);
               eptr += 3;
            } else {
               *eptr++ = *vptr;
            }
         }
         if (eptr < encodebuf + sizeof(encodebuf)) {
            *eptr = '\0';
         } else {
            encodebuf[sizeof(encodebuf) - 1] = '\0';
         }
         ast_string_field_set(cps, encoding[x], encodebuf);
         newval = cps->encoding[x];
      }
      SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
   }
   va_end(ap);

   if (!ast_strlen_zero(cps->extra))
      SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(cps->extra), 0, (void *)cps->extra, 0, NULL);
   return stmt;
}
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().

{
   for (; *chunk; chunk++) {
      if (*chunk == '^' && strchr("0123456789ABCDEF", chunk[1]) && strchr("0123456789ABCDEF", chunk[2])) {
         sscanf(chunk + 1, "%02hhX", chunk);
         memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
      }
   }
}
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
keyfieldwhere clause field
lookupvalue of field for where clause
aplist 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:
numberof rows affected
-1on failure

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

{
   struct odbc_obj *obj;
   SQLHSTMT stmt;
   char sql[256];
   SQLLEN rowcount=0;
   const char *newparam;
   int res;
   va_list aq;
   struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
   struct ast_flags connected_flag = { RES_ODBC_CONNECTED };

   va_copy(cps.ap, ap);
   va_copy(aq, ap);
   
   if (!table)
      return -1;

   obj = ast_odbc_request_obj2(database, connected_flag);
   if (!obj)
      return -1;

   snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
   while((newparam = va_arg(aq, const char *))) {
      snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
      va_arg(aq, const char *);
   }
   va_end(aq);
   snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);

   stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);

   if (!stmt) {
      ast_odbc_release_obj(obj);
      return -1;
   }

   res = SQLRowCount(stmt, &rowcount);
   SQLFreeHandle (SQL_HANDLE_STMT, stmt);
   ast_odbc_release_obj(obj);

   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
      return -1;
   }

   if (rowcount >= 0)
      return (int)rowcount;

   return -1;
}
static int load_module ( void  ) [static]

Definition at line 1160 of file res_config_odbc.c.

References ast_config_engine_register(), and ast_verb.

{
   ast_config_engine_register(&odbc_engine);
   ast_verb(1, "res_config_odbc loaded.\n");
   return 0;
}
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
aplist 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:
varon success
NULLon failure

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

{
   struct odbc_obj *obj;
   SQLHSTMT stmt;
   char sql[1024];
   char coltitle[256];
   char rowdata[2048];
   const char *initfield=NULL;
   char *op;
   const char *newparam;
   char *stringp;
   char *chunk;
   SQLSMALLINT collen;
   int res;
   int x;
   struct ast_variable *var=NULL;
   struct ast_config *cfg=NULL;
   struct ast_category *cat=NULL;
   struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
   SQLULEN colsize;
   SQLSMALLINT colcount=0;
   SQLSMALLINT datatype;
   SQLSMALLINT decimaldigits;
   SQLSMALLINT nullable;
   SQLLEN indicator;
   struct custom_prepare_struct cps = { .sql = sql };
   va_list aq;

   if (!table || ast_string_field_init(&cps, 256)) {
      return NULL;
   }
   va_copy(cps.ap, ap);
   va_copy(aq, ap);


   obj = ast_odbc_request_obj2(database, connected_flag);
   if (!obj) {
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   newparam = va_arg(aq, const char *);
   if (!newparam)  {
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }
   initfield = ast_strdupa(newparam);
   if ((op = strchr(initfield, ' '))) 
      *op = '\0';
   va_arg(aq, const char *);
   op = !strchr(newparam, ' ') ? " =" : "";
   snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
      strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
   while((newparam = va_arg(aq, const char *))) {
      op = !strchr(newparam, ' ') ? " =" : "";
      snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
         strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
      va_arg(aq, const char *);
   }
   if (initfield)
      snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
   va_end(aq);

   stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);

   if (!stmt) {
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   res = SQLNumResultCols(stmt, &colcount);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
      SQLFreeHandle(SQL_HANDLE_STMT, stmt);
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   cfg = ast_config_new();
   if (!cfg) {
      ast_log(LOG_WARNING, "Out of memory!\n");
      SQLFreeHandle(SQL_HANDLE_STMT, stmt);
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
      var = NULL;
      if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
         ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
         continue;
      }
      cat = ast_category_new("","",99999);
      if (!cat) {
         ast_log(LOG_WARNING, "Out of memory!\n");
         continue;
      }
      for (x=0;x<colcount;x++) {
         rowdata[0] = '\0';
         colsize = 0;
         collen = sizeof(coltitle);
         res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
                  &datatype, &colsize, &decimaldigits, &nullable);
         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
            ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
            ast_category_destroy(cat);
            goto next_sql_fetch;
         }

         indicator = 0;
         res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
         if (indicator == SQL_NULL_DATA)
            continue;

         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
            ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
            ast_category_destroy(cat);
            goto next_sql_fetch;
         }
         stringp = rowdata;
         while (stringp) {
            chunk = strsep(&stringp, ";");
            if (!ast_strlen_zero(ast_strip(chunk))) {
               if (strchr(chunk, '^')) {
                  decode_chunk(chunk);
               }
               if (initfield && !strcmp(initfield, coltitle)) {
                  ast_category_rename(cat, chunk);
               }
               var = ast_variable_new(coltitle, chunk, "");
               ast_variable_append(cat, var);
            }
         }
      }
      ast_category_append(cfg, cat);
next_sql_fetch:;
   }

   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
   ast_odbc_release_obj(obj);
   ast_string_field_free_memory(&cps);
   return cfg;
}
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
aplist 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:
varon success
NULLon failure

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

{
   struct odbc_obj *obj;
   SQLHSTMT stmt;
   char sql[1024];
   char coltitle[256];
   char rowdata[2048];
   char *op;
   const char *newparam;
   char *stringp;
   char *chunk;
   SQLSMALLINT collen;
   int res;
   int x;
   struct ast_variable *var=NULL, *prev=NULL;
   SQLULEN colsize;
   SQLSMALLINT colcount=0;
   SQLSMALLINT datatype;
   SQLSMALLINT decimaldigits;
   SQLSMALLINT nullable;
   SQLLEN indicator;
   va_list aq;
   struct custom_prepare_struct cps = { .sql = sql };
   struct ast_flags connected_flag = { RES_ODBC_CONNECTED };

   if (ast_string_field_init(&cps, 256)) {
      return NULL;
   }
   va_copy(cps.ap, ap);
   va_copy(aq, ap);

   if (!table) {
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   obj = ast_odbc_request_obj2(database, connected_flag);

   if (!obj) {
      ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   newparam = va_arg(aq, const char *);
   if (!newparam) {
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }
   va_arg(aq, const char *);
   op = !strchr(newparam, ' ') ? " =" : "";
   snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
      strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
   while((newparam = va_arg(aq, const char *))) {
      op = !strchr(newparam, ' ') ? " =" : "";
      snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
         strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
      va_arg(aq, const char *);
   }
   va_end(aq);

   stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);

   if (!stmt) {
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   res = SQLNumResultCols(stmt, &colcount);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
      SQLFreeHandle (SQL_HANDLE_STMT, stmt);
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }

   res = SQLFetch(stmt);
   if (res == SQL_NO_DATA) {
      SQLFreeHandle (SQL_HANDLE_STMT, stmt);
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
      SQLFreeHandle (SQL_HANDLE_STMT, stmt);
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return NULL;
   }
   for (x = 0; x < colcount; x++) {
      rowdata[0] = '\0';
      colsize = 0;
      collen = sizeof(coltitle);
      res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
               &datatype, &colsize, &decimaldigits, &nullable);
      if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
         ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
         if (var)
            ast_variables_destroy(var);
         ast_odbc_release_obj(obj);
         ast_string_field_free_memory(&cps);
         return NULL;
      }

      indicator = 0;
      res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
      if (indicator == SQL_NULL_DATA)
         rowdata[0] = '\0';
      else if (ast_strlen_zero(rowdata)) {
         /* Because we encode the empty string for a NULL, we will encode
          * actual empty strings as a string containing a single whitespace. */
         ast_copy_string(rowdata, " ", sizeof(rowdata));
      }

      if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
         ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
         if (var)
            ast_variables_destroy(var);
         ast_odbc_release_obj(obj);
         return NULL;
      }
      stringp = rowdata;
      while (stringp) {
         chunk = strsep(&stringp, ";");
         if (!ast_strlen_zero(ast_strip(chunk))) {
            if (strchr(chunk, '^')) {
               decode_chunk(chunk);
            }
            if (prev) {
               prev->next = ast_variable_new(coltitle, chunk, "");
               if (prev->next) {
                  prev = prev->next;
               }
            } else {
               prev = var = ast_variable_new(coltitle, chunk, "");
            }
         }
      }
   }


   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
   ast_odbc_release_obj(obj);
   ast_string_field_free_memory(&cps);
   return var;
}
static int reload_module ( void  ) [static]

Definition at line 1167 of file res_config_odbc.c.

{
   return 0;
}
static int require_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Definition at line 976 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, 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, type, odbc_cache_columns::type, warn_length, warn_type, and WARN_TYPE_OR_LENGTH.

{
   struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
   struct odbc_cache_columns *col;
   char *elm;
   int type, size;

   if (!tableptr) {
      return -1;
   }

   while ((elm = va_arg(ap, char *))) {
      type = va_arg(ap, require_type);
      size = va_arg(ap, int);
      /* Check if the field matches the criteria */
      AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
         if (strcmp(col->name, elm) == 0) {
            /* Type check, first.  Some fields are more particular than others */
            switch (col->type) {
            case SQL_CHAR:
            case SQL_VARCHAR:
            case SQL_LONGVARCHAR:
#ifdef HAVE_ODBC_WCHAR
            case SQL_WCHAR:
            case SQL_WVARCHAR:
            case SQL_WLONGVARCHAR:
#endif
            case SQL_BINARY:
            case SQL_VARBINARY:
            case SQL_LONGVARBINARY:
            case SQL_GUID:
#define CHECK_SIZE(n) \
                  if (col->size < n) {      \
                     warn_length(col, n);  \
                  }                         \
                  break;
               switch (type) {
               case RQ_UINTEGER1: CHECK_SIZE(3)  /*         255 */
               case RQ_INTEGER1:  CHECK_SIZE(4)  /*        -128 */
               case RQ_UINTEGER2: CHECK_SIZE(5)  /*       65535 */
               case RQ_INTEGER2:  CHECK_SIZE(6)  /*      -32768 */
               case RQ_UINTEGER3:                /*    16777215 */
               case RQ_INTEGER3:  CHECK_SIZE(8)  /*    -8388608 */
               case RQ_DATE:                     /*  2008-06-09 */
               case RQ_UINTEGER4: CHECK_SIZE(10) /*  4200000000 */
               case RQ_INTEGER4:  CHECK_SIZE(11) /* -2100000000 */
               case RQ_DATETIME:                 /* 2008-06-09 16:03:47 */
               case RQ_UINTEGER8: CHECK_SIZE(19) /* trust me    */
               case RQ_INTEGER8:  CHECK_SIZE(20) /* ditto       */
               case RQ_FLOAT:
               case RQ_CHAR:      CHECK_SIZE(size)
               }
#undef CHECK_SIZE
               break;
            case SQL_TYPE_DATE:
               if (type != RQ_DATE) {
                  warn_type(col, type);
               }
               break;
            case SQL_TYPE_TIMESTAMP:
            case SQL_TIMESTAMP:
               if (type != RQ_DATE && type != RQ_DATETIME) {
                  warn_type(col, type);
               }
               break;
            case SQL_BIT:
               warn_length(col, size);
               break;
#define WARN_TYPE_OR_LENGTH(n)   \
                  if (!ast_rq_is_int(type)) {  \
                     warn_type(col, type);    \
                  } else {                     \
                     warn_length(col, n);  \
                  }
            case SQL_TINYINT:
               if (type != RQ_UINTEGER1) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
            case SQL_C_STINYINT:
               if (type != RQ_INTEGER1) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
            case SQL_C_USHORT:
               if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
            case SQL_SMALLINT:
            case SQL_C_SSHORT:
               if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
            case SQL_C_ULONG:
               if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
                  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
                  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
                  type != RQ_INTEGER4) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
            case SQL_INTEGER:
            case SQL_C_SLONG:
               if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
                  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
                  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
                  type != RQ_INTEGER4) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
            case SQL_C_UBIGINT:
               if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
                  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
                  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
                  type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
                  type != RQ_INTEGER8) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
            case SQL_BIGINT:
            case SQL_C_SBIGINT:
               if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
                  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
                  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
                  type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
                  type != RQ_INTEGER8) {
                  WARN_TYPE_OR_LENGTH(size)
               }
               break;
#undef WARN_TYPE_OR_LENGTH
            case SQL_NUMERIC:
            case SQL_DECIMAL:
            case SQL_FLOAT:
            case SQL_REAL:
            case SQL_DOUBLE:
               if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
                  warn_type(col, type);
               }
               break;
            default:
               ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm);
            }
            break;
         }
      }
      if (!col) {
         ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
      }
   }
   va_end(ap);
   AST_RWLIST_UNLOCK(&tableptr->columns);
   return 0;
}
static int store_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Excute an INSERT query.

Parameters:
database
table
aplist 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:
numberof rows affected
-1on failure

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

{
   struct odbc_obj *obj;
   SQLHSTMT stmt;
   char sql[256];
   char keys[256];
   char vals[256];
   SQLLEN rowcount=0;
   const char *newparam;
   int res;
   va_list aq;
   struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
   struct ast_flags connected_flag = { RES_ODBC_CONNECTED };

   va_copy(cps.ap, ap);
   va_copy(aq, ap);
   
   if (!table)
      return -1;

   obj = ast_odbc_request_obj2(database, connected_flag);
   if (!obj)
      return -1;

   newparam = va_arg(aq, const char *);
   if (!newparam)  {
      ast_odbc_release_obj(obj);
      return -1;
   }
   va_arg(aq, const char *);
   snprintf(keys, sizeof(keys), "%s", newparam);
   ast_copy_string(vals, "?", sizeof(vals));
   while ((newparam = va_arg(aq, const char *))) {
      snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
      snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
      va_arg(aq, const char *);
   }
   va_end(aq);
   snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);

   stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);

   if (!stmt) {
      ast_odbc_release_obj(obj);
      return -1;
   }

   res = SQLRowCount(stmt, &rowcount);
   SQLFreeHandle (SQL_HANDLE_STMT, stmt);
   ast_odbc_release_obj(obj);

   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
      return -1;
   }

   if (rowcount >= 0)
      return (int)rowcount;

   return -1;
}
static int unload_module ( void  ) [static]

Definition at line 1152 of file res_config_odbc.c.

References ast_config_engine_deregister(), and ast_verb.

{
   ast_config_engine_deregister(&odbc_engine);

   ast_verb(1, "res_config_odbc unloaded.\n");
   return 0;
}
static int unload_odbc ( const char *  a,
const char *  b 
) [static]

Definition at line 1134 of file res_config_odbc.c.

References ast_odbc_clear_cache().

{
   return ast_odbc_clear_cache(a, b);
}
static int update2_odbc ( const char *  database,
const char *  table,
va_list  ap 
) [static]

Execute an UPDATE query.

Parameters:
database
table
aplist 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:
numberof rows affected
-1on failure

Definition at line 671 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, table, and update2_prepare().

{
   struct odbc_obj *obj;
   SQLHSTMT stmt;
   struct update2_prepare_struct ups = { .database = database, .table = table, };
   struct ast_str *sql;
   int res;
   SQLLEN rowcount = 0;

   va_copy(ups.ap, ap);

   if (!(obj = ast_odbc_request_obj(database, 0))) {
      return -1;
   }

   if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
      ast_odbc_release_obj(obj);
      return -1;
   }

   res = SQLRowCount(stmt, &rowcount);
   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
   ast_odbc_release_obj(obj);

   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
      sql = ast_str_thread_get(&sql_buf, 16);
      ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
      return -1;
   }

   if (rowcount >= 0) {
      return (int)rowcount;
   }

   return -1;
}
static SQLHSTMT update2_prepare ( struct odbc_obj obj,
void *  data 
) [static]

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

{
   int res, x = 1, first = 1;
   struct update2_prepare_struct *ups = data;
   const char *newparam, *newval;
   struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
   SQLHSTMT stmt;
   va_list ap;
   struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
   struct odbc_cache_columns *column;

   if (!sql) {
      if (tableptr) {
         ast_odbc_release_table(tableptr);
      }
      return NULL;
   }

   if (!tableptr) {
      ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'.  Update will fail!\n", ups->table, ups->database);
      return NULL;
   }

   res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
      ast_odbc_release_table(tableptr);
      return NULL;
   }

   ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);

   /* Start by finding the second set of parameters */
   va_copy(ap, ups->ap);

   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
   }

   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
      if ((column = ast_odbc_find_column(tableptr, newparam))) {
         ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam);
         SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
         first = 0;
      } else {
         ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database);
      }
   }
   va_end(ap);

   /* Restart search, because we need to add the search parameters */
   va_copy(ap, ups->ap);
   ast_str_append(&sql, 0, "WHERE");
   first = 1;

   while ((newparam = va_arg(ap, const char *))) {
      newval = va_arg(ap, const char *);
      if (!(column = ast_odbc_find_column(tableptr, newparam))) {
         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);
         ast_odbc_release_table(tableptr);
         SQLFreeHandle(SQL_HANDLE_STMT, stmt);
         return NULL;
      }
      ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam);
      SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
      first = 0;
   }
   va_end(ap);

   /* Done with the table metadata */
   ast_odbc_release_table(tableptr);

   res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
      SQLFreeHandle(SQL_HANDLE_STMT, stmt);
      return NULL;
   }

   return stmt;
}
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
keyfieldwhere clause field
lookupvalue of field for where clause
aplist 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:
numberof rows affected
-1on failure

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

{
   struct odbc_obj *obj;
   SQLHSTMT stmt;
   char sql[256];
   SQLLEN rowcount=0;
   const char *newparam;
   int res, count = 1;
   va_list aq;
   struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
   struct odbc_cache_tables *tableptr;
   struct odbc_cache_columns *column = NULL;
   struct ast_flags connected_flag = { RES_ODBC_CONNECTED };

   if (!table) {
      return -1;
   }

   va_copy(cps.ap, ap);
   va_copy(aq, ap);

   if (ast_string_field_init(&cps, 256)) {
      return -1;
   }

   tableptr = ast_odbc_find_table(database, table);
   if (!(obj = ast_odbc_request_obj2(database, connected_flag))) {
      ast_odbc_release_table(tableptr);
      ast_string_field_free_memory(&cps);
      return -1;
   }

   newparam = va_arg(aq, const char *);
   if (!newparam)  {
      ast_odbc_release_obj(obj);
      ast_odbc_release_table(tableptr);
      ast_string_field_free_memory(&cps);
      return -1;
   }
   va_arg(aq, const char *);

   if (tableptr && !(column = ast_odbc_find_column(tableptr, newparam))) {
      ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", newparam, table, database);
   }

   snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
   while((newparam = va_arg(aq, const char *))) {
      va_arg(aq, const char *);
      if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count > 63) {
         /* NULL test for integer-based columns */
         if (ast_strlen_zero(newparam) && tableptr && column && column->nullable && count < 64 &&
            (column->type == SQL_INTEGER || column->type == SQL_BIGINT ||
             column->type == SQL_SMALLINT || column->type == SQL_TINYINT ||
             column->type == SQL_NUMERIC || column->type == SQL_DECIMAL)) {
            snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=NULL", newparam);
            cps.skip |= (1LL << count);
         } else {
            snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
         }
      } else { /* the column does not exist in the table */
         cps.skip |= (1LL << count);
      }
      count++;
   }
   va_end(aq);
   snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
   ast_odbc_release_table(tableptr);

   stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);

   if (!stmt) {
      ast_odbc_release_obj(obj);
      ast_string_field_free_memory(&cps);
      return -1;
   }

   res = SQLRowCount(stmt, &rowcount);
   SQLFreeHandle (SQL_HANDLE_STMT, stmt);
   ast_odbc_release_obj(obj);
   ast_string_field_free_memory(&cps);

   if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
      ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
      return -1;
   }

   if (rowcount >= 0) {
      return (int) rowcount;
   }

   return -1;
}

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

Definition at line 1177 of file res_config_odbc.c.

struct ast_config_engine odbc_engine [static]

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

Referenced by update2_odbc(), and update2_prepare().