#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 707 of file cdr_adaptive_odbc.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 707 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 load_config(), load_module(), 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 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 *) data, SQL_NTS); 00297 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00298 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", (char *) data); 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 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_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.
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 677 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().
00678 { 00679 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00680 ast_log(LOG_ERROR, "Unable to lock column list. Load failed.\n"); 00681 return 0; 00682 } 00683 00684 load_config(); 00685 AST_RWLIST_UNLOCK(&odbc_tables); 00686 ast_cdr_register(name, ast_module_info->description, odbc_log); 00687 return 0; 00688 }
| 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 { 00462 int year = 0, month = 0, day = 0; 00463 if (sscanf(colptr, "%4d-%2d-%2d", &year, &month, &day) != 3 || year <= 0 || 00464 month <= 0 || month > 12 || day < 0 || day > 31 || 00465 ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || 00466 (month == 2 && year % 400 == 0 && day > 29) || 00467 (month == 2 && year % 100 == 0 && day > 28) || 00468 (month == 2 && year % 4 == 0 && day > 29) || 00469 (month == 2 && year % 4 != 0 && day > 28)) { 00470 ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr); 00471 continue; 00472 } 00473 00474 if (year > 0 && year < 100) { 00475 year += 2000; 00476 } 00477 00478 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00479 LENGTHEN_BUF2(17); 00480 ast_str_append(&sql2, 0, "%s{ d '%04d-%02d-%02d' }", first ? "" : ",", year, month, day); 00481 } 00482 break; 00483 case SQL_TYPE_TIME: 00484 { 00485 int hour = 0, minute = 0, second = 0; 00486 int count = sscanf(colptr, "%2d:%2d:%2d", &hour, &minute, &second); 00487 00488 if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) { 00489 ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr); 00490 continue; 00491 } 00492 00493 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00494 LENGTHEN_BUF2(15); 00495 ast_str_append(&sql2, 0, "%s{ t '%02d:%02d:%02d' }", first ? "" : ",", hour, minute, second); 00496 } 00497 break; 00498 case SQL_TYPE_TIMESTAMP: 00499 case SQL_TIMESTAMP: 00500 { 00501 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; 00502 int count = sscanf(colptr, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &minute, &second); 00503 00504 if ((count != 3 && count != 5 && count != 6) || year <= 0 || 00505 month <= 0 || month > 12 || day < 0 || day > 31 || 00506 ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || 00507 (month == 2 && year % 400 == 0 && day > 29) || 00508 (month == 2 && year % 100 == 0 && day > 28) || 00509 (month == 2 && year % 4 == 0 && day > 29) || 00510 (month == 2 && year % 4 != 0 && day > 28) || 00511 hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) { 00512 ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr); 00513 continue; 00514 } 00515 00516 if (year > 0 && year < 100) { 00517 year += 2000; 00518 } 00519 00520 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00521 LENGTHEN_BUF2(26); 00522 ast_str_append(&sql2, 0, "%s{ ts '%04d-%02d-%02d %02d:%02d:%02d' }", first ? "" : ",", year, month, day, hour, minute, second); 00523 } 00524 break; 00525 case SQL_INTEGER: 00526 { 00527 int integer = 0; 00528 if (sscanf(colptr, "%30d", &integer) != 1) { 00529 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00530 continue; 00531 } 00532 00533 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00534 LENGTHEN_BUF2(12); 00535 ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer); 00536 } 00537 break; 00538 case SQL_BIGINT: 00539 { 00540 long long integer = 0; 00541 if (sscanf(colptr, "%30lld", &integer) != 1) { 00542 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00543 continue; 00544 } 00545 00546 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00547 LENGTHEN_BUF2(24); 00548 ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", integer); 00549 } 00550 break; 00551 case SQL_SMALLINT: 00552 { 00553 short integer = 0; 00554 if (sscanf(colptr, "%30hd", &integer) != 1) { 00555 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00556 continue; 00557 } 00558 00559 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00560 LENGTHEN_BUF2(6); 00561 ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer); 00562 } 00563 break; 00564 case SQL_TINYINT: 00565 { 00566 char integer = 0; 00567 if (sscanf(colptr, "%30hhd", &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(4); 00574 ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer); 00575 } 00576 break; 00577 case SQL_BIT: 00578 { 00579 char integer = 0; 00580 if (sscanf(colptr, "%30hhd", &integer) != 1) { 00581 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00582 continue; 00583 } 00584 if (integer != 0) 00585 integer = 1; 00586 00587 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00588 LENGTHEN_BUF2(2); 00589 ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer); 00590 } 00591 break; 00592 case SQL_NUMERIC: 00593 case SQL_DECIMAL: 00594 { 00595 double number = 0.0; 00596 if (sscanf(colptr, "%30lf", &number) != 1) { 00597 ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name); 00598 continue; 00599 } 00600 00601 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00602 LENGTHEN_BUF2(entry->decimals); 00603 ast_str_append(&sql2, 0, "%s%*.*lf", first ? "" : ",", entry->decimals, entry->radix, number); 00604 } 00605 break; 00606 case SQL_FLOAT: 00607 case SQL_REAL: 00608 case SQL_DOUBLE: 00609 { 00610 double number = 0.0; 00611 if (sscanf(colptr, "%30lf", &number) != 1) { 00612 ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name); 00613 continue; 00614 } 00615 00616 ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name); 00617 LENGTHEN_BUF2(entry->decimals); 00618 ast_str_append(&sql2, 0, "%s%lf", first ? "" : ",", number); 00619 } 00620 break; 00621 default: 00622 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); 00623 continue; 00624 } 00625 first = 0; 00626 } 00627 } 00628 00629 /* Concatenate the two constructed buffers */ 00630 LENGTHEN_BUF1(ast_str_strlen(sql2)); 00631 ast_str_append(&sql, 0, ")"); 00632 ast_str_append(&sql2, 0, ")"); 00633 ast_str_append(&sql, 0, "%s", ast_str_buffer(sql2)); 00634 00635 ast_verb(11, "[%s]\n", ast_str_buffer(sql)); 00636 00637 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, ast_str_buffer(sql)); 00638 if (stmt) { 00639 SQLRowCount(stmt, &rows); 00640 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00641 } 00642 if (rows == 0) { 00643 ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql)); 00644 } 00645 early_release: 00646 ast_odbc_release_obj(obj); 00647 } 00648 AST_RWLIST_UNLOCK(&odbc_tables); 00649 00650 /* Next time, just allocate buffers that are that big to start with. */ 00651 if (ast_str_strlen(sql) > maxsize) { 00652 maxsize = ast_str_strlen(sql); 00653 } 00654 if (ast_str_strlen(sql2) > maxsize2) { 00655 maxsize2 = ast_str_strlen(sql2); 00656 } 00657 00658 ast_free(sql); 00659 ast_free(sql2); 00660 return 0; 00661 }
| static int reload | ( | void | ) | [static] |
Definition at line 690 of file cdr_adaptive_odbc.c.
References ast_log(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, free_config(), load_config(), and LOG_ERROR.
00691 { 00692 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00693 ast_log(LOG_ERROR, "Unable to lock column list. Reload failed.\n"); 00694 return -1; 00695 } 00696 00697 free_config(); 00698 load_config(); 00699 AST_RWLIST_UNLOCK(&odbc_tables); 00700 return 0; 00701 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 663 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().
00664 { 00665 ast_cdr_unregister(name); 00666 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00667 ast_cdr_register(name, ast_module_info->description, odbc_log); 00668 ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n"); 00669 return -1; 00670 } 00671 00672 free_config(); 00673 AST_RWLIST_UNLOCK(&odbc_tables); 00674 return 0; 00675 }
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 707 of file cdr_adaptive_odbc.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 707 of file cdr_adaptive_odbc.c.
int maxsize = 512 [static] |
int maxsize2 = 512 [static] |
char* name = "Adaptive ODBC" [static] |
Definition at line 53 of file cdr_adaptive_odbc.c.
Referenced by __analog_ss_thread(), __ast_change_name_nolink(), __ast_channel_alloc_ap(), __iax2_show_peers(), _sip_show_peers(), acf_curl_helper(), action_atxfer(), action_getvar(), action_hangup(), action_originate(), action_redirect(), action_sendtext(), action_setvar(), action_status(), action_timeout(), adsi_load(), aji_test(), analog_ss_thread(), ast_cel_fabricate_channel_from_event(), ast_channel_destructor(), ast_connected_line_source_parse(), ast_dsp_set_call_progress_zone(), ast_event_str_to_ie_type(), ast_getformatname_multiple(), ast_jb_read_conf(), ast_module_helper(), ast_monitor_change_fname(), ast_monitor_start(), ast_monitor_stop(), ast_parse_caller_presentation(), ast_redirecting_reason_parse(), ast_rtp_lookup_mime_multiple2(), ast_setstate(), ast_str2tos(), ast_syslog_facility(), ast_syslog_priority(), build_calendar(), callerid_read(), callerid_write(), change_monitor_action(), channel_spy(), cli_tps_ping(), cli_tps_report(), config_ldap(), connectedline_write(), do_pause_or_unpause(), dump_ies(), dump_prov_ies(), entry_cmp_fn(), fac2str(), group_cmp_fn(), handle_cli_status(), handle_redirect(), handle_register_message(), handle_showchan(), handle_tcptls_connection(), httpd_helper_thread(), load_module(), load_rpt_vars(), lua_func_read(), lua_get_variable(), lua_get_variable_value(), lua_set_variable(), lua_set_variable_value(), manager_rpt_local_nodes(), manager_rpt_status(), map_video_codec(), misdn_cfg_get_config_string(), misdn_cfg_get_name(), mwi_thread(), my_get_callerid(), oss_call(), oss_request(), parse_cookies(), parse_uri(), peek_read(), phone_request(), phoneprov_callback(), process_echocancel(), process_opcode(), process_returncode(), redirecting_id_write(), 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(), start_monitor_action(), stop_monitor_action(), tps_taskprocessor_tab_complete(), unistim_new(), unload_module(), and update_call_counter().
1.5.6