Wed Apr 6 11:29:54 2011

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_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, }
static struct ast_module_infoast_module_info = &__mod_info
static int maxsize = 512
static int maxsize2 = 512
static const 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 314 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().

#define LENGTHEN_BUF2 ( size   ) 

Definition at line 328 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 761 of file cdr_adaptive_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 761 of file cdr_adaptive_odbc.c.

static int free_config ( void   )  [static]

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

00269 {
00270    struct tables *table;
00271    struct columns *entry;
00272    while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
00273       while ((entry = AST_LIST_REMOVE_HEAD(&(table->columns), list))) {
00274          ast_free(entry);
00275       }
00276       ast_free(table);
00277    }
00278    return 0;
00279 }

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

Definition at line 281 of file cdr_adaptive_odbc.c.

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

Referenced by odbc_log().

00282 {
00283    int res, i;
00284    SQLHSTMT stmt;
00285    SQLINTEGER nativeerror = 0, numfields = 0;
00286    SQLSMALLINT diagbytes = 0;
00287    unsigned char state[10], diagnostic[256];
00288 
00289    res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
00290    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00291       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00292       return NULL;
00293    }
00294 
00295    res = SQLPrepare(stmt, (unsigned char *) data, SQL_NTS);
00296    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00297       ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", (char *) data);
00298       SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00299       for (i = 0; i < numfields; i++) {
00300          SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00301          ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00302          if (i > 10) {
00303             ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00304             break;
00305          }
00306       }
00307       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00308       return NULL;
00309    }
00310 
00311    return stmt;
00312 }

static int load_config ( void   )  [static]

Definition at line 80 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_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, tables::columns, columns, odbc_obj::con, CONFIG, config_flags, CONFIG_STATUS_FILEINVALID, tables::connection, LOG_ERROR, LOG_NOTICE, LOG_WARNING, columns::staticvalue, tables::table, usegmtime, and var.

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

static int load_module ( void   )  [static]

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

00731 {
00732    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00733       ast_log(LOG_ERROR, "Unable to lock column list.  Load failed.\n");
00734       return 0;
00735    }
00736 
00737    load_config();
00738    AST_RWLIST_UNLOCK(&odbc_tables);
00739    ast_cdr_register(name, ast_module_info->description, odbc_log);
00740    return 0;
00741 }

static int odbc_log ( struct ast_cdr cdr  )  [static]

Definition at line 341 of file cdr_adaptive_odbc.c.

References ast_cdr::answer, ast_cdr_getvar(), ast_copy_string(), ast_free, AST_LIST_TRAVERSE, ast_localtime(), 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_buffer(), ast_str_create(), ast_str_set(), ast_str_strlen(), ast_strdupa, ast_strftime(), ast_strlen_zero(), ast_tvdiff_us(), ast_tvzero(), ast_verb, columns::cdrname, tables::columns, tables::connection, columns::decimals, ast_cdr::end, columns::filtervalue, first, generic_prepare(), LENGTHEN_BUF1, LENGTHEN_BUF2, LOG_ERROR, LOG_WARNING, maxsize2, columns::name, columns::octetlen, columns::radix, ast_cdr::start, columns::staticvalue, tables::table, columns::type, and tables::usegmtime.

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

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

static int reload ( void   )  [static]

Definition at line 743 of file cdr_adaptive_odbc.c.

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

00744 {
00745    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00746       ast_log(LOG_ERROR, "Unable to lock column list.  Reload failed.\n");
00747       return -1;
00748    }
00749 
00750    free_config();
00751    load_config();
00752    AST_RWLIST_UNLOCK(&odbc_tables);
00753    return 0;
00754 }

static int unload_module ( void   )  [static]

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

00717 {
00718    ast_cdr_unregister(name);
00719    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00720       ast_cdr_register(name, ast_module_info->description, odbc_log);
00721       ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
00722       return -1;
00723    }
00724 
00725    free_config();
00726    AST_RWLIST_UNLOCK(&odbc_tables);
00727    return 0;
00728 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static]

Definition at line 761 of file cdr_adaptive_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 761 of file cdr_adaptive_odbc.c.

int maxsize = 512 [static]

Definition at line 54 of file cdr_adaptive_odbc.c.

Referenced by ast_func_read2().

int maxsize2 = 512 [static]

Definition at line 54 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().

const char name[] = "Adaptive ODBC" [static]

Definition at line 52 of file cdr_adaptive_odbc.c.

Referenced by __analog_ss_thread(), __ast_change_name_nolink(), __ast_channel_alloc_ap(), __ast_data_add_structure(), __iax2_show_peers(), _sip_show_peers(), acf_curl_helper(), action_atxfer(), action_getvar(), action_hangup(), action_originate(), action_redirect(), action_sendtext(), action_setvar(), action_status(), action_timeout(), adsi_load(), aji_cli_create_collection(), aji_cli_create_leafnode(), aji_cli_delete_pubsub_node(), aji_cli_list_pubsub_nodes(), aji_cli_purge_pubsub_nodes(), aji_test(), analog_ss_thread(), aoc_amount_str(), ast_cel_fabricate_channel_from_event(), ast_connected_line_source_parse(), ast_context_find_or_create(), ast_data_add_codecs(), ast_data_add_password(), ast_data_add_str(), ast_dsp_set_call_progress_zone(), ast_event_str_to_ie_type(), ast_getformatname_multiple(), ast_jb_read_conf(), ast_module_helper(), ast_monitor_change_fname(), ast_monitor_start(), ast_parse_caller_presentation(), ast_party_name_charset_parse(), ast_redirecting_reason_parse(), ast_rtp_lookup_mime_multiple2(), ast_setstate(), ast_str2tos(), ast_syslog_facility(), ast_syslog_priority(), build_calendar(), callerid_read(), change_monitor_action(), channel_spy(), cli_tps_ping(), cli_tps_report(), complete_trans_path_choice(), config_ldap(), count_agents_cb(), do_pause_or_unpause(), dump_ies(), dump_prov_ies(), entry_cmp_fn(), fac2str(), fax_session_tab_complete(), get_esc(), group_cmp_fn(), gtalk_ringing_ack(), handle_cli_core_show_translation(), handle_cli_osp_show(), handle_cli_status(), handle_redirect(), handle_register_message(), handle_showchan(), handle_tcptls_connection(), httpd_helper_thread(), load_module(), load_rpt_vars(), lua_func_read(), lua_get_variable(), lua_get_variable_value(), lua_set_variable(), lua_set_variable_value(), manager_mute_mixmonitor(), manager_rpt_local_nodes(), manager_rpt_status(), map_video_codec(), match_agent(), misdn_cfg_get_config_string(), misdn_cfg_get_name(), mwi_thread(), my_get_callerid(), oss_call(), oss_request(), parse_cookies(), party_id_write(), party_name_build_data(), party_name_read(), party_name_write(), peek_read(), phone_request(), phoneprov_callback(), process_echocancel(), process_opcode(), process_returncode(), register_verify(), reload_module(), rpt_call(), rpt_do_cmd(), rpt_do_dump(), rpt_do_fun(), rpt_do_fun1(), rpt_do_local_nodes(), rpt_do_lstats(), rpt_do_nodes(), rpt_do_stats(), rpt_exec(), rpt_manager_do_stats(), rpt_master(), show_config_description(), sip_prepare_socket(), sip_prune_realtime(), softhangup_exec(), start_monitor_action(), stop_monitor_action(), tps_taskprocessor_tab_complete(), unistim_new(), unload_module(), and update_call_counter().


Generated on Wed Apr 6 11:29:54 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7