#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 | __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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 __reg_module | ( | void | ) | [static] |
Definition at line 681 of file cdr_adaptive_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 681 of file cdr_adaptive_odbc.c.
static int free_config | ( | void | ) | [static] |
Definition at line 246 of file cdr_adaptive_odbc.c.
References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_REMOVE_HEAD, columns::list, and table.
Referenced by load_config(), load_module(), reload(), and unload_module().
00247 { 00248 struct tables *table; 00249 struct columns *entry; 00250 while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) { 00251 while ((entry = AST_LIST_REMOVE_HEAD(&(table->columns), list))) { 00252 ast_free(entry); 00253 } 00254 ast_free(table); 00255 } 00256 return 0; 00257 }
static SQLHSTMT generic_prepare | ( | struct odbc_obj * | obj, | |
void * | data | |||
) | [static] |
Definition at line 259 of file cdr_adaptive_odbc.c.
References ast_log(), odbc_obj::con, and LOG_WARNING.
Referenced by odbc_log().
00260 { 00261 int res, i; 00262 char *sql = data; 00263 SQLHSTMT stmt; 00264 SQLINTEGER nativeerror = 0, numfields = 0; 00265 SQLSMALLINT diagbytes = 0; 00266 unsigned char state[10], diagnostic[256]; 00267 00268 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); 00269 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00270 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00271 return NULL; 00272 } 00273 00274 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); 00275 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00276 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); 00277 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00278 for (i = 0; i < numfields; i++) { 00279 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00280 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00281 if (i > 10) { 00282 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00283 break; 00284 } 00285 } 00286 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00287 return NULL; 00288 } 00289 00290 return stmt; 00291 }
static int load_config | ( | void | ) | [static] |
Definition at line 78 of file cdr_adaptive_odbc.c.
References ast_calloc, ast_category_browse(), ast_config_load, ast_copy_string(), AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj(), ast_strdupa, ast_strip(), ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, tables::columns, columns, odbc_obj::con, CONFIG, config_flags, tables::connection, LOG_ERROR, LOG_NOTICE, LOG_WARNING, tables::table, and var.
00079 { 00080 struct ast_config *cfg; 00081 struct ast_variable *var; 00082 const char *tmp, *catg; 00083 struct tables *tableptr; 00084 struct columns *entry; 00085 struct odbc_obj *obj; 00086 char columnname[80]; 00087 char connection[40]; 00088 char table[40]; 00089 int lenconnection, lentable; 00090 SQLLEN sqlptr; 00091 int res = 0; 00092 SQLHSTMT stmt = NULL; 00093 struct ast_flags config_flags = { 0 }; /* Part of our config comes from the database */ 00094 00095 cfg = ast_config_load(CONFIG, config_flags); 00096 if (!cfg) { 00097 ast_log(LOG_WARNING, "Unable to load " CONFIG ". No adaptive ODBC CDRs.\n"); 00098 return -1; 00099 } 00100 00101 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) { 00102 var = ast_variable_browse(cfg, catg); 00103 if (!var) 00104 continue; 00105 00106 if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "connection"))) { 00107 ast_log(LOG_WARNING, "No connection parameter found in '%s'. Skipping.\n", catg); 00108 continue; 00109 } 00110 ast_copy_string(connection, tmp, sizeof(connection)); 00111 lenconnection = strlen(connection); 00112 00113 /* When loading, we want to be sure we can connect. */ 00114 obj = ast_odbc_request_obj(connection, 1); 00115 if (!obj) { 00116 ast_log(LOG_WARNING, "No such connection '%s' in the '%s' section of " CONFIG ". Check res_odbc.conf.\n", connection, catg); 00117 continue; 00118 } 00119 00120 if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "table"))) { 00121 ast_log(LOG_NOTICE, "No table name found. Assuming 'cdr'.\n"); 00122 tmp = "cdr"; 00123 } 00124 ast_copy_string(table, tmp, sizeof(table)); 00125 lentable = strlen(table); 00126 00127 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00128 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00129 ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", connection); 00130 ast_odbc_release_obj(obj); 00131 continue; 00132 } 00133 00134 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)table, SQL_NTS, (unsigned char *)"%", SQL_NTS); 00135 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00136 ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'. Skipping.\n", connection); 00137 ast_odbc_release_obj(obj); 00138 continue; 00139 } 00140 00141 tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + lenconnection + 1 + lentable + 1); 00142 if (!tableptr) { 00143 ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", table, connection); 00144 ast_odbc_release_obj(obj); 00145 res = -1; 00146 break; 00147 } 00148 00149 tableptr->connection = (char *)tableptr + sizeof(*tableptr); 00150 tableptr->table = (char *)tableptr + sizeof(*tableptr) + lenconnection + 1; 00151 ast_copy_string(tableptr->connection, connection, lenconnection + 1); 00152 ast_copy_string(tableptr->table, table, lentable + 1); 00153 00154 ast_verb(3, "Found adaptive CDR table %s@%s.\n", tableptr->table, tableptr->connection); 00155 00156 /* Check for filters first */ 00157 for (var = ast_variable_browse(cfg, catg); var; var = var->next) { 00158 if (strncmp(var->name, "filter", 6) == 0) { 00159 char *cdrvar = ast_strdupa(var->name + 6); 00160 cdrvar = ast_strip(cdrvar); 00161 ast_verb(3, "Found filter %s for cdr variable %s in %s@%s\n", var->value, cdrvar, tableptr->table, tableptr->connection); 00162 00163 entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(cdrvar) + 1 + strlen(var->value) + 1); 00164 if (!entry) { 00165 ast_log(LOG_ERROR, "Out of memory creating filter entry for CDR variable '%s' in table '%s' on connection '%s'\n", cdrvar, table, connection); 00166 res = -1; 00167 break; 00168 } 00169 00170 /* NULL column entry means this isn't a column in the database */ 00171 entry->name = NULL; 00172 entry->cdrname = (char *)entry + sizeof(*entry); 00173 entry->filtervalue = (char *)entry + sizeof(*entry) + strlen(cdrvar) + 1; 00174 strcpy(entry->cdrname, cdrvar); 00175 strcpy(entry->filtervalue, var->value); 00176 00177 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list); 00178 } 00179 } 00180 00181 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) { 00182 char *cdrvar = ""; 00183 00184 SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr); 00185 00186 /* Is there an alias for this column? */ 00187 00188 /* NOTE: This seems like a non-optimal parse method, but I'm going 00189 * for user configuration readability, rather than fast parsing. We 00190 * really don't parse this file all that often, anyway. 00191 */ 00192 for (var = ast_variable_browse(cfg, catg); var; var = var->next) { 00193 if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, columnname) == 0) { 00194 char *alias = ast_strdupa(var->name + 5); 00195 cdrvar = ast_strip(alias); 00196 ast_verb(3, "Found alias %s for column %s in %s@%s\n", cdrvar, columnname, tableptr->table, tableptr->connection); 00197 break; 00198 } 00199 } 00200 00201 entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1 + strlen(cdrvar) + 1); 00202 if (!entry) { 00203 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, table, connection); 00204 res = -1; 00205 break; 00206 } 00207 entry->name = (char *)entry + sizeof(*entry); 00208 strcpy(entry->name, columnname); 00209 00210 if (!ast_strlen_zero(cdrvar)) { 00211 entry->cdrname = entry->name + strlen(columnname) + 1; 00212 strcpy(entry->cdrname, cdrvar); 00213 } else /* Point to same place as the column name */ 00214 entry->cdrname = (char *)entry + sizeof(*entry); 00215 00216 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL); 00217 SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL); 00218 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL); 00219 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL); 00220 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL); 00221 SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL); 00222 00223 /* Specification states that the octenlen should be the maximum number of bytes 00224 * returned in a char or binary column, but it seems that some drivers just set 00225 * it to NULL. (Bad Postgres! No biscuit!) */ 00226 if (entry->octetlen == 0) 00227 entry->octetlen = entry->size; 00228 00229 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); 00230 /* Insert column info into column list */ 00231 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list); 00232 res = 0; 00233 } 00234 00235 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00236 ast_odbc_release_obj(obj); 00237 00238 if (AST_LIST_FIRST(&(tableptr->columns))) 00239 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list); 00240 else 00241 ast_free(tableptr); 00242 } 00243 return res; 00244 }
static int load_module | ( | void | ) | [static] |
Definition at line 651 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().
00652 { 00653 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00654 ast_log(LOG_ERROR, "Unable to lock column list. Load failed.\n"); 00655 return 0; 00656 } 00657 00658 load_config(); 00659 AST_RWLIST_UNLOCK(&odbc_tables); 00660 ast_cdr_register(name, ast_module_info->description, odbc_log); 00661 return 0; 00662 }
static int odbc_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 320 of file cdr_adaptive_odbc.c.
References ast_cdr_getvar(), ast_free, AST_LIST_TRAVERSE, 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_create(), ast_str_set(), ast_strlen_zero(), ast_verb, columns::cdrname, tables::columns, tables::connection, columns::decimals, columns::filtervalue, generic_prepare(), LENGTHEN_BUF1, LENGTHEN_BUF2, LOG_ERROR, LOG_WARNING, maxsize2, columns::name, columns::octetlen, columns::radix, ast_str::str, tables::table, columns::type, and ast_str::used.
Referenced by load_module(), odbc_load_module(), and unload_module().
00321 { 00322 struct tables *tableptr; 00323 struct columns *entry; 00324 struct odbc_obj *obj; 00325 struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2); 00326 char *tmp; 00327 char colbuf[1024], *colptr; 00328 SQLHSTMT stmt = NULL; 00329 SQLLEN rows = 0; 00330 00331 if (!sql || !sql2) { 00332 if (sql) 00333 ast_free(sql); 00334 if (sql2) 00335 ast_free(sql2); 00336 return -1; 00337 } 00338 00339 if (AST_RWLIST_RDLOCK(&odbc_tables)) { 00340 ast_log(LOG_ERROR, "Unable to lock table list. Insert CDR(s) failed.\n"); 00341 ast_free(sql); 00342 ast_free(sql2); 00343 return -1; 00344 } 00345 00346 AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) { 00347 ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table); 00348 ast_str_set(&sql2, 0, " VALUES ("); 00349 00350 /* No need to check the connection now; we'll handle any failure in prepare_and_execute */ 00351 if (!(obj = ast_odbc_request_obj(tableptr->connection, 0))) { 00352 ast_log(LOG_WARNING, "cdr_adaptive_odbc: Unable to retrieve database handle for '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str); 00353 continue; 00354 } 00355 00356 AST_LIST_TRAVERSE(&(tableptr->columns), entry, list) { 00357 /* Check if we have a similarly named variable */ 00358 ast_cdr_getvar(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), 0, 00359 (strcasecmp(entry->cdrname, "start") == 0 || 00360 strcasecmp(entry->cdrname, "answer") == 0 || 00361 strcasecmp(entry->cdrname, "end") == 0) ? 0 : 1); 00362 00363 if (colptr) { 00364 /* Check first if the column filters this entry. Note that this 00365 * is very specifically NOT ast_strlen_zero(), because the filter 00366 * could legitimately specify that the field is blank, which is 00367 * different from the field being unspecified (NULL). */ 00368 if (entry->filtervalue && strcasecmp(colptr, entry->filtervalue) != 0) { 00369 ast_verb(4, "CDR column '%s' with value '%s' does not match filter of" 00370 " '%s'. Cancelling this CDR.\n", 00371 entry->cdrname, colptr, entry->filtervalue); 00372 goto early_release; 00373 } 00374 00375 /* Only a filter? */ 00376 if (ast_strlen_zero(entry->name)) 00377 continue; 00378 00379 LENGTHEN_BUF1(strlen(entry->name)); 00380 00381 switch (entry->type) { 00382 case SQL_CHAR: 00383 case SQL_VARCHAR: 00384 case SQL_LONGVARCHAR: 00385 case SQL_BINARY: 00386 case SQL_VARBINARY: 00387 case SQL_LONGVARBINARY: 00388 case SQL_GUID: 00389 /* For these two field names, get the rendered form, instead of the raw 00390 * form (but only when we're dealing with a character-based field). 00391 */ 00392 if (strcasecmp(entry->name, "disposition") == 0) 00393 ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0); 00394 else if (strcasecmp(entry->name, "amaflags") == 0) 00395 ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0); 00396 00397 /* Truncate too-long fields */ 00398 if (entry->type != SQL_GUID) { 00399 if (strlen(colptr) > entry->octetlen) 00400 colptr[entry->octetlen] = '\0'; 00401 } 00402 00403 ast_str_append(&sql, 0, "%s,", entry->name); 00404 LENGTHEN_BUF2(strlen(colptr)); 00405 00406 /* Encode value, with escaping */ 00407 ast_str_append(&sql2, 0, "'"); 00408 for (tmp = colptr; *tmp; tmp++) { 00409 if (*tmp == '\'') { 00410 ast_str_append(&sql2, 0, "''"); 00411 } else if (*tmp == '\\' && ast_odbc_backslash_is_escape(obj)) { 00412 ast_str_append(&sql2, 0, "\\\\"); 00413 } else { 00414 ast_str_append(&sql2, 0, "%c", *tmp); 00415 } 00416 } 00417 ast_str_append(&sql2, 0, "',"); 00418 break; 00419 case SQL_TYPE_DATE: 00420 if (ast_strlen_zero(colptr)) { 00421 continue; 00422 } else { 00423 int year = 0, month = 0, day = 0; 00424 if (sscanf(colptr, "%4d-%2d-%2d", &year, &month, &day) != 3 || year <= 0 || 00425 month <= 0 || month > 12 || day < 0 || day > 31 || 00426 ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || 00427 (month == 2 && year % 400 == 0 && day > 29) || 00428 (month == 2 && year % 100 == 0 && day > 28) || 00429 (month == 2 && year % 4 == 0 && day > 29) || 00430 (month == 2 && year % 4 != 0 && day > 28)) { 00431 ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr); 00432 break; 00433 } 00434 00435 if (year > 0 && year < 100) 00436 year += 2000; 00437 00438 ast_str_append(&sql, 0, "%s,", entry->name); 00439 LENGTHEN_BUF2(17); 00440 ast_str_append(&sql2, 0, "{ d '%04d-%02d-%02d' },", year, month, day); 00441 } 00442 break; 00443 case SQL_TYPE_TIME: 00444 if (ast_strlen_zero(colptr)) { 00445 continue; 00446 } else { 00447 int hour = 0, minute = 0, second = 0; 00448 int count = sscanf(colptr, "%2d:%2d:%2d", &hour, &minute, &second); 00449 00450 if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) { 00451 ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr); 00452 break; 00453 } 00454 00455 ast_str_append(&sql, 0, "%s,", entry->name); 00456 LENGTHEN_BUF2(15); 00457 ast_str_append(&sql2, 0, "{ t '%02d:%02d:%02d' },", hour, minute, second); 00458 } 00459 break; 00460 case SQL_TYPE_TIMESTAMP: 00461 case SQL_TIMESTAMP: 00462 if (ast_strlen_zero(colptr)) { 00463 continue; 00464 } else { 00465 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; 00466 int count = sscanf(colptr, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &minute, &second); 00467 00468 if ((count != 3 && count != 5 && count != 6) || year <= 0 || 00469 month <= 0 || month > 12 || day < 0 || day > 31 || 00470 ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || 00471 (month == 2 && year % 400 == 0 && day > 29) || 00472 (month == 2 && year % 100 == 0 && day > 28) || 00473 (month == 2 && year % 4 == 0 && day > 29) || 00474 (month == 2 && year % 4 != 0 && day > 28) || 00475 hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) { 00476 ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr); 00477 break; 00478 } 00479 00480 if (year > 0 && year < 100) 00481 year += 2000; 00482 00483 ast_str_append(&sql, 0, "%s,", entry->name); 00484 LENGTHEN_BUF2(26); 00485 ast_str_append(&sql2, 0, "{ ts '%04d-%02d-%02d %02d:%02d:%02d' },", year, month, day, hour, minute, second); 00486 } 00487 break; 00488 case SQL_INTEGER: 00489 if (ast_strlen_zero(colptr)) { 00490 continue; 00491 } else { 00492 int integer = 0; 00493 if (sscanf(colptr, "%30d", &integer) != 1) { 00494 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00495 break; 00496 } 00497 00498 ast_str_append(&sql, 0, "%s,", entry->name); 00499 LENGTHEN_BUF2(12); 00500 ast_str_append(&sql2, 0, "%d,", integer); 00501 } 00502 break; 00503 case SQL_BIGINT: 00504 if (ast_strlen_zero(colptr)) { 00505 continue; 00506 } else { 00507 long long integer = 0; 00508 if (sscanf(colptr, "%30lld", &integer) != 1) { 00509 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00510 break; 00511 } 00512 00513 ast_str_append(&sql, 0, "%s,", entry->name); 00514 LENGTHEN_BUF2(24); 00515 ast_str_append(&sql2, 0, "%lld,", integer); 00516 } 00517 break; 00518 case SQL_SMALLINT: 00519 if (ast_strlen_zero(colptr)) { 00520 continue; 00521 } else { 00522 short integer = 0; 00523 if (sscanf(colptr, "%30hd", &integer) != 1) { 00524 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00525 break; 00526 } 00527 00528 ast_str_append(&sql, 0, "%s,", entry->name); 00529 LENGTHEN_BUF2(6); 00530 ast_str_append(&sql2, 0, "%d,", integer); 00531 } 00532 break; 00533 case SQL_TINYINT: 00534 if (ast_strlen_zero(colptr)) { 00535 continue; 00536 } else { 00537 char integer = 0; 00538 if (sscanf(colptr, "%30hhd", &integer) != 1) { 00539 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00540 break; 00541 } 00542 00543 ast_str_append(&sql, 0, "%s,", entry->name); 00544 LENGTHEN_BUF2(4); 00545 ast_str_append(&sql2, 0, "%d,", integer); 00546 } 00547 break; 00548 case SQL_BIT: 00549 if (ast_strlen_zero(colptr)) { 00550 continue; 00551 } else { 00552 char integer = 0; 00553 if (sscanf(colptr, "%30hhd", &integer) != 1) { 00554 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00555 break; 00556 } 00557 if (integer != 0) 00558 integer = 1; 00559 00560 ast_str_append(&sql, 0, "%s,", entry->name); 00561 LENGTHEN_BUF2(2); 00562 ast_str_append(&sql2, 0, "%d,", integer); 00563 } 00564 break; 00565 case SQL_NUMERIC: 00566 case SQL_DECIMAL: 00567 if (ast_strlen_zero(colptr)) { 00568 continue; 00569 } else { 00570 double number = 0.0; 00571 if (sscanf(colptr, "%30lf", &number) != 1) { 00572 ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name); 00573 break; 00574 } 00575 00576 ast_str_append(&sql, 0, "%s,", entry->name); 00577 LENGTHEN_BUF2(entry->decimals); 00578 ast_str_append(&sql2, 0, "%*.*lf,", entry->decimals, entry->radix, number); 00579 } 00580 break; 00581 case SQL_FLOAT: 00582 case SQL_REAL: 00583 case SQL_DOUBLE: 00584 if (ast_strlen_zero(colptr)) { 00585 continue; 00586 } else { 00587 double number = 0.0; 00588 if (sscanf(colptr, "%30lf", &number) != 1) { 00589 ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name); 00590 break; 00591 } 00592 00593 ast_str_append(&sql, 0, "%s,", entry->name); 00594 LENGTHEN_BUF2(entry->decimals); 00595 ast_str_append(&sql2, 0, "%lf,", number); 00596 } 00597 break; 00598 default: 00599 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); 00600 } 00601 } 00602 } 00603 00604 /* Concatenate the two constructed buffers */ 00605 LENGTHEN_BUF1(sql2->used); 00606 sql->str[sql->used - 1] = ')'; 00607 sql2->str[sql2->used - 1] = ')'; 00608 ast_str_append(&sql, 0, "%s", sql2->str); 00609 00610 ast_verb(11, "[%s]\n", sql->str); 00611 00612 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql->str); 00613 if (stmt) { 00614 SQLRowCount(stmt, &rows); 00615 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00616 } 00617 if (rows == 0) { 00618 ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str); 00619 } 00620 early_release: 00621 ast_odbc_release_obj(obj); 00622 } 00623 AST_RWLIST_UNLOCK(&odbc_tables); 00624 00625 /* Next time, just allocate buffers that are that big to start with. */ 00626 if (sql->used > maxsize) 00627 maxsize = sql->used; 00628 if (sql2->used > maxsize2) 00629 maxsize2 = sql2->used; 00630 00631 ast_free(sql); 00632 ast_free(sql2); 00633 return 0; 00634 }
static int reload | ( | void | ) | [static] |
Definition at line 664 of file cdr_adaptive_odbc.c.
References ast_log(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, free_config(), load_config(), and LOG_ERROR.
00665 { 00666 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00667 ast_log(LOG_ERROR, "Unable to lock column list. Reload failed.\n"); 00668 return -1; 00669 } 00670 00671 free_config(); 00672 load_config(); 00673 AST_RWLIST_UNLOCK(&odbc_tables); 00674 return 0; 00675 }
static int unload_module | ( | void | ) | [static] |
Definition at line 636 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().
00637 { 00638 ast_cdr_unregister(name); 00639 usleep(1); 00640 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00641 ast_cdr_register(name, ast_module_info->description, odbc_log); 00642 ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n"); 00643 return -1; 00644 } 00645 00646 free_config(); 00647 AST_RWLIST_UNLOCK(&odbc_tables); 00648 return 0; 00649 }
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 681 of file cdr_adaptive_odbc.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 681 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.