#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 | __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_info * | ast_module_info = &__mod_info |
| static int | maxsize = 512 |
| static int | maxsize2 = 512 |
| static char * | name = "Adaptive ODBC" |
Definition in file cdr_adaptive_odbc.c.
| #define CONFIG "cdr_adaptive_odbc.conf" |
| #define LENGTHEN_BUF1 | ( | size | ) |
| #define LENGTHEN_BUF2 | ( | size | ) |
| static void __fini_odbc_tables | ( | void | ) | [static] |
| static void __init_odbc_tables | ( | void | ) | [static] |
| 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 }
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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
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] |
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().
1.5.6