Adaptive ODBC CDR backend. More...
#include "asterisk.h"#include <sys/types.h>#include <time.h>#include <sql.h>#include <sqlext.h>#include <sqltypes.h>#include "asterisk/config.h"#include "asterisk/channel.h"#include "asterisk/lock.h"#include "asterisk/linkedlists.h"#include "asterisk/res_odbc.h"#include "asterisk/cdr.h"#include "asterisk/module.h"
Go to the source code of this file.
Data Structures | |
| struct | columns |
| struct | odbc_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_info * | ast_module_info = &__mod_info |
| static int | maxsize = 512 |
| static int | maxsize2 = 512 |
| static char * | name = "Adaptive ODBC" |
Adaptive ODBC CDR backend.
Definition in file cdr_adaptive_odbc.c.
| #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().
| 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 }
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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
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().
1.6.2