#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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } |
static const 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 661 of file cdr_adaptive_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 661 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, 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 *tmp = ast_strdupa(var->name + 5); 00195 cdrvar = ast_strip(tmp); 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 631 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().
00632 { 00633 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00634 ast_log(LOG_ERROR, "Unable to lock column list. Load failed.\n"); 00635 return 0; 00636 } 00637 00638 load_config(); 00639 AST_RWLIST_UNLOCK(&odbc_tables); 00640 ast_cdr_register(name, ast_module_info->description, odbc_log); 00641 return 0; 00642 }
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 { 00421 int year = 0, month = 0, day = 0; 00422 if (sscanf(colptr, "%d-%d-%d", &year, &month, &day) != 3 || year <= 0 || 00423 month <= 0 || month > 12 || day < 0 || day > 31 || 00424 ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || 00425 (month == 2 && year % 400 == 0 && day > 29) || 00426 (month == 2 && year % 100 == 0 && day > 28) || 00427 (month == 2 && year % 4 == 0 && day > 29) || 00428 (month == 2 && year % 4 != 0 && day > 28)) { 00429 ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr); 00430 break; 00431 } 00432 00433 if (year > 0 && year < 100) 00434 year += 2000; 00435 00436 ast_str_append(&sql, 0, "%s,", entry->name); 00437 LENGTHEN_BUF2(17); 00438 ast_str_append(&sql2, 0, "{ d '%04d-%02d-%02d' },", year, month, day); 00439 } 00440 break; 00441 case SQL_TYPE_TIME: 00442 { 00443 int hour = 0, minute = 0, second = 0; 00444 int count = sscanf(colptr, "%d:%d:%d", &hour, &minute, &second); 00445 00446 if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) { 00447 ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr); 00448 break; 00449 } 00450 00451 ast_str_append(&sql, 0, "%s,", entry->name); 00452 LENGTHEN_BUF2(15); 00453 ast_str_append(&sql2, 0, "{ t '%02d:%02d:%02d' },", hour, minute, second); 00454 } 00455 break; 00456 case SQL_TYPE_TIMESTAMP: 00457 case SQL_TIMESTAMP: 00458 { 00459 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; 00460 int count = sscanf(colptr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second); 00461 00462 if ((count != 3 && count != 5 && count != 6) || year <= 0 || 00463 month <= 0 || month > 12 || day < 0 || day > 31 || 00464 ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || 00465 (month == 2 && year % 400 == 0 && day > 29) || 00466 (month == 2 && year % 100 == 0 && day > 28) || 00467 (month == 2 && year % 4 == 0 && day > 29) || 00468 (month == 2 && year % 4 != 0 && day > 28) || 00469 hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) { 00470 ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr); 00471 break; 00472 } 00473 00474 if (year > 0 && year < 100) 00475 year += 2000; 00476 00477 ast_str_append(&sql, 0, "%s,", entry->name); 00478 LENGTHEN_BUF2(26); 00479 ast_str_append(&sql2, 0, "{ ts '%04d-%02d-%02d %02d:%02d:%02d' },", year, month, day, hour, minute, second); 00480 } 00481 break; 00482 case SQL_INTEGER: 00483 { 00484 int integer = 0; 00485 if (sscanf(colptr, "%d", &integer) != 1) { 00486 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00487 break; 00488 } 00489 00490 ast_str_append(&sql, 0, "%s,", entry->name); 00491 LENGTHEN_BUF2(12); 00492 ast_str_append(&sql2, 0, "%d,", integer); 00493 } 00494 break; 00495 case SQL_BIGINT: 00496 { 00497 long long integer = 0; 00498 if (sscanf(colptr, "%lld", &integer) != 1) { 00499 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00500 break; 00501 } 00502 00503 ast_str_append(&sql, 0, "%s,", entry->name); 00504 LENGTHEN_BUF2(24); 00505 ast_str_append(&sql2, 0, "%lld,", integer); 00506 } 00507 break; 00508 case SQL_SMALLINT: 00509 { 00510 short integer = 0; 00511 if (sscanf(colptr, "%hd", &integer) != 1) { 00512 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00513 break; 00514 } 00515 00516 ast_str_append(&sql, 0, "%s,", entry->name); 00517 LENGTHEN_BUF2(6); 00518 ast_str_append(&sql2, 0, "%d,", integer); 00519 } 00520 break; 00521 case SQL_TINYINT: 00522 { 00523 char integer = 0; 00524 if (sscanf(colptr, "%hhd", &integer) != 1) { 00525 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00526 break; 00527 } 00528 00529 ast_str_append(&sql, 0, "%s,", entry->name); 00530 LENGTHEN_BUF2(4); 00531 ast_str_append(&sql2, 0, "%d,", integer); 00532 } 00533 break; 00534 case SQL_BIT: 00535 { 00536 char integer = 0; 00537 if (sscanf(colptr, "%hhd", &integer) != 1) { 00538 ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name); 00539 break; 00540 } 00541 if (integer != 0) 00542 integer = 1; 00543 00544 ast_str_append(&sql, 0, "%s,", entry->name); 00545 LENGTHEN_BUF2(2); 00546 ast_str_append(&sql2, 0, "%d,", integer); 00547 } 00548 break; 00549 case SQL_NUMERIC: 00550 case SQL_DECIMAL: 00551 { 00552 double number = 0.0; 00553 if (sscanf(colptr, "%lf", &number) != 1) { 00554 ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name); 00555 break; 00556 } 00557 00558 ast_str_append(&sql, 0, "%s,", entry->name); 00559 LENGTHEN_BUF2(entry->decimals); 00560 ast_str_append(&sql2, 0, "%*.*lf,", entry->decimals, entry->radix, number); 00561 } 00562 break; 00563 case SQL_FLOAT: 00564 case SQL_REAL: 00565 case SQL_DOUBLE: 00566 { 00567 double number = 0.0; 00568 if (sscanf(colptr, "%lf", &number) != 1) { 00569 ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name); 00570 break; 00571 } 00572 00573 ast_str_append(&sql, 0, "%s,", entry->name); 00574 LENGTHEN_BUF2(entry->decimals); 00575 ast_str_append(&sql2, 0, "%lf,", number); 00576 } 00577 break; 00578 default: 00579 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); 00580 } 00581 } 00582 } 00583 00584 /* Concatenate the two constructed buffers */ 00585 LENGTHEN_BUF1(sql2->used); 00586 sql->str[sql->used - 1] = ')'; 00587 sql2->str[sql2->used - 1] = ')'; 00588 ast_str_append(&sql, 0, "%s", sql2->str); 00589 00590 ast_verb(11, "[%s]\n", sql->str); 00591 00592 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql->str); 00593 if (stmt) { 00594 SQLRowCount(stmt, &rows); 00595 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00596 } 00597 if (rows == 0) { 00598 ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str); 00599 } 00600 early_release: 00601 ast_odbc_release_obj(obj); 00602 } 00603 AST_RWLIST_UNLOCK(&odbc_tables); 00604 00605 /* Next time, just allocate buffers that are that big to start with. */ 00606 if (sql->used > maxsize) 00607 maxsize = sql->used; 00608 if (sql2->used > maxsize2) 00609 maxsize2 = sql2->used; 00610 00611 ast_free(sql); 00612 ast_free(sql2); 00613 return 0; 00614 }
static int reload | ( | void | ) | [static] |
Definition at line 644 of file cdr_adaptive_odbc.c.
References ast_log(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, free_config(), load_config(), and LOG_ERROR.
00645 { 00646 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00647 ast_log(LOG_ERROR, "Unable to lock column list. Reload failed.\n"); 00648 return -1; 00649 } 00650 00651 free_config(); 00652 load_config(); 00653 AST_RWLIST_UNLOCK(&odbc_tables); 00654 return 0; 00655 }
static int unload_module | ( | void | ) | [static] |
Definition at line 616 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().
00617 { 00618 ast_cdr_unregister(name); 00619 usleep(1); 00620 if (AST_RWLIST_WRLOCK(&odbc_tables)) { 00621 ast_cdr_register(name, ast_module_info->description, odbc_log); 00622 ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n"); 00623 return -1; 00624 } 00625 00626 free_config(); 00627 AST_RWLIST_UNLOCK(&odbc_tables); 00628 return 0; 00629 }
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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 661 of file cdr_adaptive_odbc.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 661 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.