Thu Oct 11 06:48:06 2012

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"

Include dependency graph for cdr_adaptive_odbc.c:

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 __fini_odbc_tables (void)
static void __init_odbc_tables (void)
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 = AST_BUILDOPT_SUM, .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 315 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().

#define LENGTHEN_BUF2 ( size   ) 

Definition at line 329 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().


Function Documentation

static void __fini_odbc_tables ( void   )  [static]

Definition at line 78 of file cdr_adaptive_odbc.c.

00081 {

static void __init_odbc_tables ( void   )  [static]

Definition at line 78 of file cdr_adaptive_odbc.c.

00081 {

static void __reg_module ( void   )  [static]

Definition at line 728 of file cdr_adaptive_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 728 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, and tables::columns.

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

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_free, AST_LIST_FIRST, AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj(), AST_RWLIST_INSERT_TAIL, ast_strdupa, ast_strip(), ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, columns::cdrname, tables::columns, odbc_obj::con, CONFIG, CONFIG_STATUS_FILEINVALID, tables::connection, columns::decimals, columns::filtervalue, LOG_ERROR, LOG_NOTICE, LOG_WARNING, columns::name, ast_variable::name, ast_variable::next, columns::nullable, columns::octetlen, columns::radix, columns::size, columns::staticvalue, tables::table, columns::type, tables::usegmtime, usegmtime, ast_variable::value, 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 698 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().

00699 {
00700    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00701       ast_log(LOG_ERROR, "Unable to lock column list.  Load failed.\n");
00702       return 0;
00703    }
00704 
00705    load_config();
00706    AST_RWLIST_UNLOCK(&odbc_tables);
00707    ast_cdr_register(name, ast_module_info->description, odbc_log);
00708    return 0;
00709 }

static int odbc_log ( struct ast_cdr cdr  )  [static]

Definition at line 342 of file cdr_adaptive_odbc.c.

References ast_cdr::answer, ast_cdr_getvar(), 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_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().

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

static int reload ( void   )  [static]

Definition at line 711 of file cdr_adaptive_odbc.c.

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

00712 {
00713    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00714       ast_log(LOG_ERROR, "Unable to lock column list.  Reload failed.\n");
00715       return -1;
00716    }
00717 
00718    free_config();
00719    load_config();
00720    AST_RWLIST_UNLOCK(&odbc_tables);
00721    return 0;
00722 }

static int unload_module ( void   )  [static]

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

00684 {
00685    ast_cdr_unregister(name);
00686    usleep(1);
00687    if (AST_RWLIST_WRLOCK(&odbc_tables)) {
00688       ast_cdr_register(name, ast_module_info->description, odbc_log);
00689       ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
00690       return -1;
00691    }
00692 
00693    free_config();
00694    AST_RWLIST_UNLOCK(&odbc_tables);
00695    return 0;
00696 }


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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 728 of file cdr_adaptive_odbc.c.

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

Referenced by __ast_channel_alloc_ap(), __iax2_show_peers(), _sip_show_peers(), acf_curl_exec(), action_atxfer(), action_getvar(), action_hangup(), action_originate(), action_redirect(), action_sendtext(), action_setvar(), action_status(), action_timeout(), adsi_load(), aelsub_exec(), aji_test(), ast_change_name(), ast_channel_free(), ast_do_masquerade(), ast_dsp_set_call_progress_zone(), ast_event_str_to_event_type(), 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_rtp_lookup_mime_multiple(), ast_setstate(), ast_str2tos(), callerid_read(), callerid_write(), change_monitor_action(), channel_spy(), cli_tps_ping(), cli_tps_report(), config_ldap(), do_pause_or_unpause(), dump_ies(), dump_prov_ies(), entry_cmp_fn(), fac2str(), get_dahdi_channel_locked(), group_cmp_fn(), 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_rpt_local_nodes(), manager_rpt_status(), map_video_codec(), mgcp_new(), misdn_cfg_get_config_string(), misdn_cfg_get_name(), mwi_thread(), oss_call(), oss_request(), parse_cookies(), parse_uri(), peek_read(), phone_request(), phoneprov_callback(), process_echocancel(), process_opcode(), process_returncode(), register_verify(), 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(), ss_thread(), start_monitor_action(), stop_monitor_action(), tps_taskprocessor_tab_complete(), unistim_new(), unload_module(), and update_call_counter().


Generated on Thu Oct 11 06:48:06 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6