Wed Aug 18 22:34:05 2010

Asterisk developer's documentation


cdr_adaptive_odbc.c File Reference

Adaptive ODBC CDR backend. More...

#include "asterisk.h"
#include <sys/types.h>
#include <time.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/res_odbc.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"

Go to the source code of this file.

Data Structures

struct  columns
struct  odbc_tables
struct  tables
struct  tables::odbc_columns

Defines

#define CONFIG   "cdr_adaptive_odbc.conf"
#define LENGTHEN_BUF1(size)
#define LENGTHEN_BUF2(size)

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int free_config (void)
static SQLHSTMT generic_prepare (struct odbc_obj *obj, void *data)
static int load_config (void)
static int load_module (void)
static int odbc_log (struct ast_cdr *cdr)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Adaptive ODBC CDR backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
static int maxsize = 512
static int maxsize2 = 512
static char * name = "Adaptive ODBC"


Detailed Description

Adaptive ODBC CDR backend.

Author:
Tilghman Lesher <cdr_adaptive_odbc__v1@the-tilghman.com>

Definition in file cdr_adaptive_odbc.c.


Define Documentation

#define CONFIG   "cdr_adaptive_odbc.conf"

Definition at line 50 of file cdr_adaptive_odbc.c.

Referenced by load_config().

#define LENGTHEN_BUF1 ( size   ) 

Definition at line 293 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().

#define LENGTHEN_BUF2 ( size   ) 

Definition at line 307 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 681 of file cdr_adaptive_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 681 of file cdr_adaptive_odbc.c.

static int free_config ( void   )  [static]

Definition at line 246 of file cdr_adaptive_odbc.c.

References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_REMOVE_HEAD, columns::list, and table.

Referenced by load_config(), load_module(), reload(), and unload_module().

00247 {
00248    struct tables *table;
00249    struct columns *entry;
00250    while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
00251       while ((entry = AST_LIST_REMOVE_HEAD(&(table->columns), list))) {
00252          ast_free(entry);
00253       }
00254       ast_free(table);
00255    }
00256    return 0;
00257 }

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

Definition at line 259 of file cdr_adaptive_odbc.c.

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

Referenced by odbc_log().

00260 {
00261    int res, i;
00262    char *sql = data;
00263    SQLHSTMT stmt;
00264    SQLINTEGER nativeerror = 0, numfields = 0;
00265    SQLSMALLINT diagbytes = 0;
00266    unsigned char state[10], diagnostic[256];
00267 
00268    res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00269    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00270       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00271       return NULL;
00272    }
00273 
00274    res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
00275    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00276       ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
00277       SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00278       for (i = 0; i < numfields; i++) {
00279          SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00280          ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00281          if (i > 10) {
00282             ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00283             break;
00284          }
00285       }
00286       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00287       return NULL;
00288    }
00289 
00290    return stmt;
00291 }

static int load_config ( void   )  [static]

Definition at line 78 of file cdr_adaptive_odbc.c.

References ast_calloc, ast_category_browse(), ast_config_load, ast_copy_string(), AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj(), ast_strdupa, ast_strip(), ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, tables::columns, columns, odbc_obj::con, CONFIG, config_flags, tables::connection, LOG_ERROR, LOG_NOTICE, LOG_WARNING, tables::table, and var.

00079 {
00080    struct ast_config *cfg;
00081    struct ast_variable *var;
00082    const char *tmp, *catg;
00083    struct tables *tableptr;
00084    struct columns *entry;
00085    struct odbc_obj *obj;
00086    char columnname[80];
00087    char connection[40];
00088    char table[40];
00089    int lenconnection, lentable;
00090    SQLLEN sqlptr;
00091    int res = 0;
00092    SQLHSTMT stmt = NULL;
00093    struct ast_flags config_flags = { 0 }; /* Part of our config comes from the database */
00094 
00095    cfg = ast_config_load(CONFIG, config_flags);
00096    if (!cfg) {
00097       ast_log(LOG_WARNING, "Unable to load " CONFIG ".  No adaptive ODBC CDRs.\n");
00098       return -1;
00099    }
00100 
00101    for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
00102       var = ast_variable_browse(cfg, catg);
00103       if (!var)
00104          continue;
00105 
00106       if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "connection"))) {
00107          ast_log(LOG_WARNING, "No connection parameter found in '%s'.  Skipping.\n", catg);
00108          continue;
00109       }
00110       ast_copy_string(connection, tmp, sizeof(connection));
00111       lenconnection = strlen(connection);
00112 
00113       /* When loading, we want to be sure we can connect. */
00114       obj = ast_odbc_request_obj(connection, 1);
00115       if (!obj) {
00116          ast_log(LOG_WARNING, "No such connection '%s' in the '%s' section of " CONFIG ".  Check res_odbc.conf.\n", connection, catg);
00117          continue;
00118       }
00119 
00120       if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "table"))) {
00121          ast_log(LOG_NOTICE, "No table name found.  Assuming 'cdr'.\n");
00122          tmp = "cdr";
00123       }
00124       ast_copy_string(table, tmp, sizeof(table));
00125       lentable = strlen(table);
00126 
00127       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00128       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00129          ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", connection);
00130          ast_odbc_release_obj(obj);
00131          continue;
00132       }
00133 
00134       res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)table, SQL_NTS, (unsigned char *)"%", SQL_NTS);
00135       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00136          ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.  Skipping.\n", connection);
00137          ast_odbc_release_obj(obj);
00138          continue;
00139       }
00140 
00141       tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + lenconnection + 1 + lentable + 1);
00142       if (!tableptr) {
00143          ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", table, connection);
00144          ast_odbc_release_obj(obj);
00145          res = -1;
00146          break;
00147       }
00148 
00149       tableptr->connection = (char *)tableptr + sizeof(*tableptr);
00150       tableptr->table = (char *)tableptr + sizeof(*tableptr) + lenconnection + 1;
00151       ast_copy_string(tableptr->connection, connection, lenconnection + 1);
00152       ast_copy_string(tableptr->table, table, lentable + 1);
00153 
00154       ast_verb(3, "Found adaptive CDR table %s@%s.\n", tableptr->table, tableptr->connection);
00155 
00156       /* Check for filters first */
00157       for (var = ast_variable_browse(cfg, catg); var; var = var->next) {
00158          if (strncmp(var->name, "filter", 6) == 0) {
00159             char *cdrvar = ast_strdupa(var->name + 6);
00160             cdrvar = ast_strip(cdrvar);
00161             ast_verb(3, "Found filter %s for cdr variable %s in %s@%s\n", var->value, cdrvar, tableptr->table, tableptr->connection);
00162 
00163             entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(cdrvar) + 1 + strlen(var->value) + 1);
00164             if (!entry) {
00165                ast_log(LOG_ERROR, "Out of memory creating filter entry for CDR variable '%s' in table '%s' on connection '%s'\n", cdrvar, table, connection);
00166                res = -1;
00167                break;
00168             }
00169 
00170             /* NULL column entry means this isn't a column in the database */
00171             entry->name = NULL;
00172             entry->cdrname = (char *)entry + sizeof(*entry);
00173             entry->filtervalue = (char *)entry + sizeof(*entry) + strlen(cdrvar) + 1;
00174             strcpy(entry->cdrname, cdrvar);
00175             strcpy(entry->filtervalue, var->value);
00176 
00177             AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
00178          }
00179       }
00180 
00181       while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
00182          char *cdrvar = "";
00183 
00184          SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
00185 
00186          /* Is there an alias for this column? */
00187 
00188          /* NOTE: This seems like a non-optimal parse method, but I'm going
00189           * for user configuration readability, rather than fast parsing. We
00190           * really don't parse this file all that often, anyway.
00191           */
00192          for (var = ast_variable_browse(cfg, catg); var; var = var->next) {
00193             if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, columnname) == 0) {
00194                char *alias = ast_strdupa(var->name + 5);
00195                cdrvar = ast_strip(alias);
00196                ast_verb(3, "Found alias %s for column %s in %s@%s\n", cdrvar, columnname, tableptr->table, tableptr->connection);
00197                break;
00198             }
00199          }
00200 
00201          entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1 + strlen(cdrvar) + 1);
00202          if (!entry) {
00203             ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, table, connection);
00204             res = -1;
00205             break;
00206          }
00207          entry->name = (char *)entry + sizeof(*entry);
00208          strcpy(entry->name, columnname);
00209 
00210          if (!ast_strlen_zero(cdrvar)) {
00211             entry->cdrname = entry->name + strlen(columnname) + 1;
00212             strcpy(entry->cdrname, cdrvar);
00213          } else /* Point to same place as the column name */
00214             entry->cdrname = (char *)entry + sizeof(*entry);
00215 
00216          SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
00217          SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
00218          SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
00219          SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
00220          SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
00221          SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
00222 
00223          /* Specification states that the octenlen should be the maximum number of bytes
00224           * returned in a char or binary column, but it seems that some drivers just set
00225           * it to NULL. (Bad Postgres! No biscuit!) */
00226          if (entry->octetlen == 0)
00227             entry->octetlen = entry->size;
00228 
00229          ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
00230          /* Insert column info into column list */
00231          AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
00232          res = 0;
00233       }
00234 
00235       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00236       ast_odbc_release_obj(obj);
00237 
00238       if (AST_LIST_FIRST(&(tableptr->columns)))
00239          AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
00240       else
00241          ast_free(tableptr);
00242    }
00243    return res;
00244 }

static int load_module ( void   )  [static]

Definition at line 651 of file cdr_adaptive_odbc.c.

References ast_cdr_register(), ast_log(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, load_config(), LOG_ERROR, and odbc_log().

00652 {
00653    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00654       ast_log(LOG_ERROR, "Unable to lock column list.  Load failed.\n");
00655       return 0;
00656    }
00657 
00658    load_config();
00659    AST_RWLIST_UNLOCK(&odbc_tables);
00660    ast_cdr_register(name, ast_module_info->description, odbc_log);
00661    return 0;
00662 }

static int odbc_log ( struct ast_cdr cdr  )  [static]

Definition at line 320 of file cdr_adaptive_odbc.c.

References ast_cdr_getvar(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_str_append(), ast_str_create(), ast_str_set(), ast_strlen_zero(), ast_verb, columns::cdrname, tables::columns, tables::connection, columns::decimals, columns::filtervalue, generic_prepare(), LENGTHEN_BUF1, LENGTHEN_BUF2, LOG_ERROR, LOG_WARNING, maxsize2, columns::name, columns::octetlen, columns::radix, ast_str::str, tables::table, columns::type, and ast_str::used.

Referenced by load_module(), odbc_load_module(), and unload_module().

00321 {
00322    struct tables *tableptr;
00323    struct columns *entry;
00324    struct odbc_obj *obj;
00325    struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
00326    char *tmp;
00327    char colbuf[1024], *colptr;
00328    SQLHSTMT stmt = NULL;
00329    SQLLEN rows = 0;
00330 
00331    if (!sql || !sql2) {
00332       if (sql)
00333          ast_free(sql);
00334       if (sql2)
00335          ast_free(sql2);
00336       return -1;
00337    }
00338 
00339    if (AST_RWLIST_RDLOCK(&odbc_tables)) {
00340       ast_log(LOG_ERROR, "Unable to lock table list.  Insert CDR(s) failed.\n");
00341       ast_free(sql);
00342       ast_free(sql2);
00343       return -1;
00344    }
00345 
00346    AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) {
00347       ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table);
00348       ast_str_set(&sql2, 0, " VALUES (");
00349 
00350       /* No need to check the connection now; we'll handle any failure in prepare_and_execute */
00351       if (!(obj = ast_odbc_request_obj(tableptr->connection, 0))) {
00352          ast_log(LOG_WARNING, "cdr_adaptive_odbc: Unable to retrieve database handle for '%s:%s'.  CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str);
00353          continue;
00354       }
00355 
00356       AST_LIST_TRAVERSE(&(tableptr->columns), entry, list) {
00357          /* Check if we have a similarly named variable */
00358          ast_cdr_getvar(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), 0,
00359             (strcasecmp(entry->cdrname, "start") == 0 ||
00360              strcasecmp(entry->cdrname, "answer") == 0 ||
00361              strcasecmp(entry->cdrname, "end") == 0) ? 0 : 1);
00362 
00363          if (colptr) {
00364             /* Check first if the column filters this entry.  Note that this
00365              * is very specifically NOT ast_strlen_zero(), because the filter
00366              * could legitimately specify that the field is blank, which is
00367              * different from the field being unspecified (NULL). */
00368             if (entry->filtervalue && strcasecmp(colptr, entry->filtervalue) != 0) {
00369                ast_verb(4, "CDR column '%s' with value '%s' does not match filter of"
00370                   " '%s'.  Cancelling this CDR.\n",
00371                   entry->cdrname, colptr, entry->filtervalue);
00372                goto early_release;
00373             }
00374 
00375             /* Only a filter? */
00376             if (ast_strlen_zero(entry->name))
00377                continue;
00378 
00379             LENGTHEN_BUF1(strlen(entry->name));
00380 
00381             switch (entry->type) {
00382             case SQL_CHAR:
00383             case SQL_VARCHAR:
00384             case SQL_LONGVARCHAR:
00385             case SQL_BINARY:
00386             case SQL_VARBINARY:
00387             case SQL_LONGVARBINARY:
00388             case SQL_GUID:
00389                /* For these two field names, get the rendered form, instead of the raw
00390                 * form (but only when we're dealing with a character-based field).
00391                 */
00392                if (strcasecmp(entry->name, "disposition") == 0)
00393                   ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
00394                else if (strcasecmp(entry->name, "amaflags") == 0)
00395                   ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
00396 
00397                /* Truncate too-long fields */
00398                if (entry->type != SQL_GUID) {
00399                   if (strlen(colptr) > entry->octetlen)
00400                      colptr[entry->octetlen] = '\0';
00401                }
00402 
00403                ast_str_append(&sql, 0, "%s,", entry->name);
00404                LENGTHEN_BUF2(strlen(colptr));
00405 
00406                /* Encode value, with escaping */
00407                ast_str_append(&sql2, 0, "'");
00408                for (tmp = colptr; *tmp; tmp++) {
00409                   if (*tmp == '\'') {
00410                      ast_str_append(&sql2, 0, "''");
00411                   } else if (*tmp == '\\' && ast_odbc_backslash_is_escape(obj)) {
00412                      ast_str_append(&sql2, 0, "\\\\");
00413                   } else {
00414                      ast_str_append(&sql2, 0, "%c", *tmp);
00415                   }
00416                }
00417                ast_str_append(&sql2, 0, "',");
00418                break;
00419             case SQL_TYPE_DATE:
00420                if (ast_strlen_zero(colptr)) {
00421                   continue;
00422                } else {
00423                   int year = 0, month = 0, day = 0;
00424                   if (sscanf(colptr, "%4d-%2d-%2d", &year, &month, &day) != 3 || year <= 0 ||
00425                      month <= 0 || month > 12 || day < 0 || day > 31 ||
00426                      ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
00427                      (month == 2 && year % 400 == 0 && day > 29) ||
00428                      (month == 2 && year % 100 == 0 && day > 28) ||
00429                      (month == 2 && year % 4 == 0 && day > 29) ||
00430                      (month == 2 && year % 4 != 0 && day > 28)) {
00431                      ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr);
00432                      break;
00433                   }
00434 
00435                   if (year > 0 && year < 100)
00436                      year += 2000;
00437 
00438                   ast_str_append(&sql, 0, "%s,", entry->name);
00439                   LENGTHEN_BUF2(17);
00440                   ast_str_append(&sql2, 0, "{ d '%04d-%02d-%02d' },", year, month, day);
00441                }
00442                break;
00443             case SQL_TYPE_TIME:
00444                if (ast_strlen_zero(colptr)) {
00445                   continue;
00446                } else {
00447                   int hour = 0, minute = 0, second = 0;
00448                   int count = sscanf(colptr, "%2d:%2d:%2d", &hour, &minute, &second);
00449 
00450                   if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
00451                      ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr);
00452                      break;
00453                   }
00454 
00455                   ast_str_append(&sql, 0, "%s,", entry->name);
00456                   LENGTHEN_BUF2(15);
00457                   ast_str_append(&sql2, 0, "{ t '%02d:%02d:%02d' },", hour, minute, second);
00458                }
00459                break;
00460             case SQL_TYPE_TIMESTAMP:
00461             case SQL_TIMESTAMP:
00462                if (ast_strlen_zero(colptr)) {
00463                   continue;
00464                } else {
00465                   int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
00466                   int count = sscanf(colptr, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &minute, &second);
00467 
00468                   if ((count != 3 && count != 5 && count != 6) || year <= 0 ||
00469                      month <= 0 || month > 12 || day < 0 || day > 31 ||
00470                      ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
00471                      (month == 2 && year % 400 == 0 && day > 29) ||
00472                      (month == 2 && year % 100 == 0 && day > 28) ||
00473                      (month == 2 && year % 4 == 0 && day > 29) ||
00474                      (month == 2 && year % 4 != 0 && day > 28) ||
00475                      hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) {
00476                      ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
00477                      break;
00478                   }
00479 
00480                   if (year > 0 && year < 100)
00481                      year += 2000;
00482 
00483                   ast_str_append(&sql, 0, "%s,", entry->name);
00484                   LENGTHEN_BUF2(26);
00485                   ast_str_append(&sql2, 0, "{ ts '%04d-%02d-%02d %02d:%02d:%02d' },", year, month, day, hour, minute, second);
00486                }
00487                break;
00488             case SQL_INTEGER:
00489                if (ast_strlen_zero(colptr)) {
00490                   continue;
00491                } else {
00492                   int integer = 0;
00493                   if (sscanf(colptr, "%30d", &integer) != 1) {
00494                      ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
00495                      break;
00496                   }
00497 
00498                   ast_str_append(&sql, 0, "%s,", entry->name);
00499                   LENGTHEN_BUF2(12);
00500                   ast_str_append(&sql2, 0, "%d,", integer);
00501                }
00502                break;
00503             case SQL_BIGINT:
00504                if (ast_strlen_zero(colptr)) {
00505                   continue;
00506                } else {
00507                   long long integer = 0;
00508                   if (sscanf(colptr, "%30lld", &integer) != 1) {
00509                      ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
00510                      break;
00511                   }
00512 
00513                   ast_str_append(&sql, 0, "%s,", entry->name);
00514                   LENGTHEN_BUF2(24);
00515                   ast_str_append(&sql2, 0, "%lld,", integer);
00516                }
00517                break;
00518             case SQL_SMALLINT:
00519                if (ast_strlen_zero(colptr)) {
00520                   continue;
00521                } else {
00522                   short integer = 0;
00523                   if (sscanf(colptr, "%30hd", &integer) != 1) {
00524                      ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
00525                      break;
00526                   }
00527 
00528                   ast_str_append(&sql, 0, "%s,", entry->name);
00529                   LENGTHEN_BUF2(6);
00530                   ast_str_append(&sql2, 0, "%d,", integer);
00531                }
00532                break;
00533             case SQL_TINYINT:
00534                if (ast_strlen_zero(colptr)) {
00535                   continue;
00536                } else {
00537                   char integer = 0;
00538                   if (sscanf(colptr, "%30hhd", &integer) != 1) {
00539                      ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
00540                      break;
00541                   }
00542 
00543                   ast_str_append(&sql, 0, "%s,", entry->name);
00544                   LENGTHEN_BUF2(4);
00545                   ast_str_append(&sql2, 0, "%d,", integer);
00546                }
00547                break;
00548             case SQL_BIT:
00549                if (ast_strlen_zero(colptr)) {
00550                   continue;
00551                } else {
00552                   char integer = 0;
00553                   if (sscanf(colptr, "%30hhd", &integer) != 1) {
00554                      ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
00555                      break;
00556                   }
00557                   if (integer != 0)
00558                      integer = 1;
00559 
00560                   ast_str_append(&sql, 0, "%s,", entry->name);
00561                   LENGTHEN_BUF2(2);
00562                   ast_str_append(&sql2, 0, "%d,", integer);
00563                }
00564                break;
00565             case SQL_NUMERIC:
00566             case SQL_DECIMAL:
00567                if (ast_strlen_zero(colptr)) {
00568                   continue;
00569                } else {
00570                   double number = 0.0;
00571                   if (sscanf(colptr, "%30lf", &number) != 1) {
00572                      ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
00573                      break;
00574                   }
00575 
00576                   ast_str_append(&sql, 0, "%s,", entry->name);
00577                   LENGTHEN_BUF2(entry->decimals);
00578                   ast_str_append(&sql2, 0, "%*.*lf,", entry->decimals, entry->radix, number);
00579                }
00580                break;
00581             case SQL_FLOAT:
00582             case SQL_REAL:
00583             case SQL_DOUBLE:
00584                if (ast_strlen_zero(colptr)) {
00585                   continue;
00586                } else {
00587                   double number = 0.0;
00588                   if (sscanf(colptr, "%30lf", &number) != 1) {
00589                      ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
00590                      break;
00591                   }
00592 
00593                   ast_str_append(&sql, 0, "%s,", entry->name);
00594                   LENGTHEN_BUF2(entry->decimals);
00595                   ast_str_append(&sql2, 0, "%lf,", number);
00596                }
00597                break;
00598             default:
00599                ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
00600             }
00601          }
00602       }
00603 
00604       /* Concatenate the two constructed buffers */
00605       LENGTHEN_BUF1(sql2->used);
00606       sql->str[sql->used - 1] = ')';
00607       sql2->str[sql2->used - 1] = ')';
00608       ast_str_append(&sql, 0, "%s", sql2->str);
00609 
00610       ast_verb(11, "[%s]\n", sql->str);
00611 
00612       stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql->str);
00613       if (stmt) {
00614          SQLRowCount(stmt, &rows);
00615          SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00616       }
00617       if (rows == 0) {
00618          ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'.  CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str);
00619       }
00620 early_release:
00621       ast_odbc_release_obj(obj);
00622    }
00623    AST_RWLIST_UNLOCK(&odbc_tables);
00624 
00625    /* Next time, just allocate buffers that are that big to start with. */
00626    if (sql->used > maxsize)
00627       maxsize = sql->used;
00628    if (sql2->used > maxsize2)
00629       maxsize2 = sql2->used;
00630 
00631    ast_free(sql);
00632    ast_free(sql2);
00633    return 0;
00634 }

static int reload ( void   )  [static]

Definition at line 664 of file cdr_adaptive_odbc.c.

References ast_log(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, free_config(), load_config(), and LOG_ERROR.

00665 {
00666    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00667       ast_log(LOG_ERROR, "Unable to lock column list.  Reload failed.\n");
00668       return -1;
00669    }
00670 
00671    free_config();
00672    load_config();
00673    AST_RWLIST_UNLOCK(&odbc_tables);
00674    return 0;
00675 }

static int unload_module ( void   )  [static]

Definition at line 636 of file cdr_adaptive_odbc.c.

References ast_cdr_register(), ast_cdr_unregister(), ast_log(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, free_config(), LOG_ERROR, and odbc_log().

00637 {
00638    ast_cdr_unregister(name);
00639    usleep(1);
00640    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00641       ast_cdr_register(name, ast_module_info->description, odbc_log);
00642       ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
00643       return -1;
00644    }
00645 
00646    free_config();
00647    AST_RWLIST_UNLOCK(&odbc_tables);
00648    return 0;
00649 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Adaptive ODBC CDR backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 681 of file cdr_adaptive_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 681 of file cdr_adaptive_odbc.c.

int maxsize = 512 [static]

Definition at line 54 of file cdr_adaptive_odbc.c.

int maxsize2 = 512 [static]

Definition at line 54 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().

char* name = "Adaptive ODBC" [static]

Definition at line 52 of file cdr_adaptive_odbc.c.


Generated on Wed Aug 18 22:34:05 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7