00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 158135 $")
00034
00035 #include <sys/types.h>
00036 #include <time.h>
00037
00038 #include <sql.h>
00039 #include <sqlext.h>
00040 #include <sqltypes.h>
00041
00042 #include "asterisk/config.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/linkedlists.h"
00046 #include "asterisk/res_odbc.h"
00047 #include "asterisk/cdr.h"
00048 #include "asterisk/module.h"
00049
00050 #define CONFIG "cdr_adaptive_odbc.conf"
00051
00052 static char *name = "Adaptive ODBC";
00053
00054 static int maxsize = 512, maxsize2 = 512;
00055
00056 struct columns {
00057 char *name;
00058 char *cdrname;
00059 char *filtervalue;
00060 SQLSMALLINT type;
00061 SQLINTEGER size;
00062 SQLSMALLINT decimals;
00063 SQLSMALLINT radix;
00064 SQLSMALLINT nullable;
00065 SQLINTEGER octetlen;
00066 AST_LIST_ENTRY(columns) list;
00067 };
00068
00069 struct tables {
00070 char *connection;
00071 char *table;
00072 AST_LIST_HEAD_NOLOCK(odbc_columns, columns) columns;
00073 AST_RWLIST_ENTRY(tables) list;
00074 };
00075
00076 static AST_RWLIST_HEAD_STATIC(odbc_tables, tables);
00077
00078 static int load_config(void)
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 };
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
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
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
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
00187
00188
00189
00190
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
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
00224
00225
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
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 }
00245
00246 static int free_config(void)
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 }
00258
00259 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
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 }
00292
00293 #define LENGTHEN_BUF1(size) \
00294 do { \
00295 \
00296 if (sql->used + size + 1 > sql->len) { \
00297 if (ast_str_make_space(&sql, ((sql->len + size + 1) / 512 + 1) * 512) != 0) { \
00298 ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
00299 ast_free(sql); \
00300 ast_free(sql2); \
00301 AST_RWLIST_UNLOCK(&odbc_tables); \
00302 return -1; \
00303 } \
00304 } \
00305 } while (0)
00306
00307 #define LENGTHEN_BUF2(size) \
00308 do { \
00309 if (sql2->used + size + 1 > sql2->len) { \
00310 if (ast_str_make_space(&sql2, ((sql2->len + size + 3) / 512 + 1) * 512) != 0) { \
00311 ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
00312 ast_free(sql); \
00313 ast_free(sql2); \
00314 AST_RWLIST_UNLOCK(&odbc_tables); \
00315 return -1; \
00316 } \
00317 } \
00318 } while (0)
00319
00320 static int odbc_log(struct ast_cdr *cdr)
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
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
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
00365
00366
00367
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
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
00390
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
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
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
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
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 }
00615
00616 static int unload_module(void)
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 }
00630
00631 static int load_module(void)
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 }
00643
00644 static int reload(void)
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 }
00656
00657 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Adaptive ODBC CDR backend",
00658 .load = load_module,
00659 .unload = unload_module,
00660 .reload = reload,
00661 );
00662