Fri Nov 12 11:54:24 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"
Include dependency graph for cdr_adaptive_odbc.c:

Go to the source code of this file.

Data Structures

struct  columns
struct  odbc_columns
struct  odbc_tables
struct  tables

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 = "0901e4e500243c855563a2d78b0c03e4" , .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 51 of file cdr_adaptive_odbc.c.

Referenced by load_config().

#define LENGTHEN_BUF1 ( size   ) 

Definition at line 316 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().

#define LENGTHEN_BUF2 ( size   ) 

Definition at line 330 of file cdr_adaptive_odbc.c.

Referenced by odbc_log(), and pgsql_log().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 729 of file cdr_adaptive_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 729 of file cdr_adaptive_odbc.c.

static int free_config ( void   )  [static]

Definition at line 269 of file cdr_adaptive_odbc.c.

References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_REMOVE_HEAD, and tables::columns.

Referenced by reload(), and unload_module().

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

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

Definition at line 282 of file cdr_adaptive_odbc.c.

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

Referenced by odbc_log().

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

static int load_config ( void   )  [static]

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

Referenced by load_module(), and reload().

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

static int load_module ( void   )  [static]

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

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

static int odbc_log ( struct ast_cdr cdr  )  [static]

Definition at line 343 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_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(), and unload_module().

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

static int reload ( void   )  [static]

Definition at line 712 of file cdr_adaptive_odbc.c.

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

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

static int unload_module ( void   )  [static]

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

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


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

Definition at line 729 of file cdr_adaptive_odbc.c.

Definition at line 729 of file cdr_adaptive_odbc.c.

int maxsize = 512 [static]

Definition at line 55 of file cdr_adaptive_odbc.c.

int maxsize2 = 512 [static]

Definition at line 55 of file cdr_adaptive_odbc.c.

Referenced by odbc_log().

char* name = "Adaptive ODBC" [static]

Definition at line 53 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(), 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_monitor_stop(), 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(), pri_fixup_principle(), 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 by  doxygen 1.6.2