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
00032
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 217647 $")
00038
00039 #include "asterisk/file.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/res_odbc.h"
00046 #include "asterisk/utils.h"
00047
00048 AST_THREADSTORAGE(sql_buf);
00049
00050 struct custom_prepare_struct {
00051 const char *sql;
00052 const char *extra;
00053 va_list ap;
00054 unsigned long long skip;
00055 };
00056
00057 static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
00058 {
00059 int res, x = 1, count = 0;
00060 struct custom_prepare_struct *cps = data;
00061 const char *newparam, *newval;
00062 SQLHSTMT stmt;
00063 va_list ap;
00064
00065 va_copy(ap, cps->ap);
00066
00067 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00068 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00069 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00070 return NULL;
00071 }
00072
00073 ast_debug(1, "Skip: %lld; SQL: %s\n", cps->skip, cps->sql);
00074
00075 res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
00076 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00077 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
00078 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00079 return NULL;
00080 }
00081
00082 while ((newparam = va_arg(ap, const char *))) {
00083 newval = va_arg(ap, const char *);
00084 if ((1LL << count++) & cps->skip) {
00085 ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1LL << (count - 1), cps->skip);
00086 continue;
00087 }
00088 ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, newparam, newval);
00089 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00090 }
00091 va_end(ap);
00092
00093 if (!ast_strlen_zero(cps->extra))
00094 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(cps->extra), 0, (void *)cps->extra, 0, NULL);
00095 return stmt;
00096 }
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
00112 {
00113 struct odbc_obj *obj;
00114 SQLHSTMT stmt;
00115 char sql[1024];
00116 char coltitle[256];
00117 char rowdata[2048];
00118 char *op;
00119 const char *newparam, *newval;
00120 char *stringp;
00121 char *chunk;
00122 SQLSMALLINT collen;
00123 int res;
00124 int x;
00125 struct ast_variable *var=NULL, *prev=NULL;
00126 SQLULEN colsize;
00127 SQLSMALLINT colcount=0;
00128 SQLSMALLINT datatype;
00129 SQLSMALLINT decimaldigits;
00130 SQLSMALLINT nullable;
00131 SQLLEN indicator;
00132 va_list aq;
00133 struct custom_prepare_struct cps = { .sql = sql };
00134
00135 va_copy(cps.ap, ap);
00136 va_copy(aq, ap);
00137
00138 if (!table)
00139 return NULL;
00140
00141 obj = ast_odbc_request_obj(database, 0);
00142
00143 if (!obj) {
00144 ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
00145 return NULL;
00146 }
00147
00148 newparam = va_arg(aq, const char *);
00149 if (!newparam) {
00150 ast_odbc_release_obj(obj);
00151 return NULL;
00152 }
00153 newval = va_arg(aq, const char *);
00154 op = !strchr(newparam, ' ') ? " =" : "";
00155 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
00156 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00157 while((newparam = va_arg(aq, const char *))) {
00158 op = !strchr(newparam, ' ') ? " =" : "";
00159 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
00160 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00161 newval = va_arg(aq, const char *);
00162 }
00163 va_end(aq);
00164
00165 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00166
00167 if (!stmt) {
00168 ast_odbc_release_obj(obj);
00169 return NULL;
00170 }
00171
00172 res = SQLNumResultCols(stmt, &colcount);
00173 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00174 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00175 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00176 ast_odbc_release_obj(obj);
00177 return NULL;
00178 }
00179
00180 res = SQLFetch(stmt);
00181 if (res == SQL_NO_DATA) {
00182 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00183 ast_odbc_release_obj(obj);
00184 return NULL;
00185 }
00186 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00187 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00188 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00189 ast_odbc_release_obj(obj);
00190 return NULL;
00191 }
00192 for (x = 0; x < colcount; x++) {
00193 rowdata[0] = '\0';
00194 collen = sizeof(coltitle);
00195 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
00196 &datatype, &colsize, &decimaldigits, &nullable);
00197 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00198 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00199 if (var)
00200 ast_variables_destroy(var);
00201 ast_odbc_release_obj(obj);
00202 return NULL;
00203 }
00204
00205 indicator = 0;
00206 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00207 if (indicator == SQL_NULL_DATA)
00208 rowdata[0] = '\0';
00209 else if (ast_strlen_zero(rowdata)) {
00210
00211
00212 ast_copy_string(rowdata, " ", sizeof(rowdata));
00213 }
00214
00215 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00216 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00217 if (var)
00218 ast_variables_destroy(var);
00219 ast_odbc_release_obj(obj);
00220 return NULL;
00221 }
00222 stringp = rowdata;
00223 while(stringp) {
00224 chunk = strsep(&stringp, ";");
00225 if (!ast_strlen_zero(ast_strip(chunk))) {
00226 if (prev) {
00227 prev->next = ast_variable_new(coltitle, chunk, "");
00228 if (prev->next)
00229 prev = prev->next;
00230 } else
00231 prev = var = ast_variable_new(coltitle, chunk, "");
00232 }
00233 }
00234 }
00235
00236
00237 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00238 ast_odbc_release_obj(obj);
00239 return var;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
00257 {
00258 struct odbc_obj *obj;
00259 SQLHSTMT stmt;
00260 char sql[1024];
00261 char coltitle[256];
00262 char rowdata[2048];
00263 const char *initfield=NULL;
00264 char *op;
00265 const char *newparam, *newval;
00266 char *stringp;
00267 char *chunk;
00268 SQLSMALLINT collen;
00269 int res;
00270 int x;
00271 struct ast_variable *var=NULL;
00272 struct ast_config *cfg=NULL;
00273 struct ast_category *cat=NULL;
00274 SQLULEN colsize;
00275 SQLSMALLINT colcount=0;
00276 SQLSMALLINT datatype;
00277 SQLSMALLINT decimaldigits;
00278 SQLSMALLINT nullable;
00279 SQLLEN indicator;
00280 struct custom_prepare_struct cps = { .sql = sql };
00281 va_list aq;
00282
00283 va_copy(cps.ap, ap);
00284 va_copy(aq, ap);
00285
00286 if (!table)
00287 return NULL;
00288
00289 obj = ast_odbc_request_obj(database, 0);
00290 if (!obj)
00291 return NULL;
00292
00293 newparam = va_arg(aq, const char *);
00294 if (!newparam) {
00295 ast_odbc_release_obj(obj);
00296 return NULL;
00297 }
00298 initfield = ast_strdupa(newparam);
00299 if ((op = strchr(initfield, ' ')))
00300 *op = '\0';
00301 newval = va_arg(aq, const char *);
00302 op = !strchr(newparam, ' ') ? " =" : "";
00303 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
00304 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00305 while((newparam = va_arg(aq, const char *))) {
00306 op = !strchr(newparam, ' ') ? " =" : "";
00307 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
00308 strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00309 newval = va_arg(aq, const char *);
00310 }
00311 if (initfield)
00312 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00313 va_end(aq);
00314
00315 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00316
00317 if (!stmt) {
00318 ast_odbc_release_obj(obj);
00319 return NULL;
00320 }
00321
00322 res = SQLNumResultCols(stmt, &colcount);
00323 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00324 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00325 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00326 ast_odbc_release_obj(obj);
00327 return NULL;
00328 }
00329
00330 cfg = ast_config_new();
00331 if (!cfg) {
00332 ast_log(LOG_WARNING, "Out of memory!\n");
00333 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00334 ast_odbc_release_obj(obj);
00335 return NULL;
00336 }
00337
00338 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
00339 var = NULL;
00340 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00341 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00342 continue;
00343 }
00344 cat = ast_category_new("","",99999);
00345 if (!cat) {
00346 ast_log(LOG_WARNING, "Out of memory!\n");
00347 continue;
00348 }
00349 for (x=0;x<colcount;x++) {
00350 rowdata[0] = '\0';
00351 collen = sizeof(coltitle);
00352 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
00353 &datatype, &colsize, &decimaldigits, &nullable);
00354 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00355 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00356 ast_category_destroy(cat);
00357 continue;
00358 }
00359
00360 indicator = 0;
00361 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00362 if (indicator == SQL_NULL_DATA)
00363 continue;
00364
00365 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00366 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00367 ast_category_destroy(cat);
00368 continue;
00369 }
00370 stringp = rowdata;
00371 while(stringp) {
00372 chunk = strsep(&stringp, ";");
00373 if (!ast_strlen_zero(ast_strip(chunk))) {
00374 if (initfield && !strcmp(initfield, coltitle))
00375 ast_category_rename(cat, chunk);
00376 var = ast_variable_new(coltitle, chunk, "");
00377 ast_variable_append(cat, var);
00378 }
00379 }
00380 }
00381 ast_category_append(cfg, cat);
00382 }
00383
00384 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00385 ast_odbc_release_obj(obj);
00386 return cfg;
00387 }
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
00405 {
00406 struct odbc_obj *obj;
00407 SQLHSTMT stmt;
00408 char sql[256];
00409 SQLLEN rowcount=0;
00410 const char *newparam, *newval;
00411 int res, count = 1;
00412 va_list aq;
00413 struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00414 struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
00415 struct odbc_cache_columns *column;
00416
00417 va_copy(cps.ap, ap);
00418 va_copy(aq, ap);
00419
00420 if (!table) {
00421 ast_odbc_release_table(tableptr);
00422 return -1;
00423 }
00424
00425 obj = ast_odbc_request_obj(database, 0);
00426 if (!obj) {
00427 ast_odbc_release_table(tableptr);
00428 return -1;
00429 }
00430
00431 newparam = va_arg(aq, const char *);
00432 if (!newparam) {
00433 ast_odbc_release_obj(obj);
00434 ast_odbc_release_table(tableptr);
00435 return -1;
00436 }
00437 newval = va_arg(aq, const char *);
00438
00439 if (tableptr && !(column = ast_odbc_find_column(tableptr, newparam))) {
00440 ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", newparam, table, database);
00441 }
00442
00443 snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
00444 while((newparam = va_arg(aq, const char *))) {
00445 newval = va_arg(aq, const char *);
00446 if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count > 63) {
00447 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
00448 } else {
00449 cps.skip |= (1LL << count);
00450 }
00451 count++;
00452 }
00453 va_end(aq);
00454 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
00455 ast_odbc_release_table(tableptr);
00456
00457 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00458
00459 if (!stmt) {
00460 ast_odbc_release_obj(obj);
00461 return -1;
00462 }
00463
00464 res = SQLRowCount(stmt, &rowcount);
00465 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00466 ast_odbc_release_obj(obj);
00467
00468 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00469 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00470 return -1;
00471 }
00472
00473 if (rowcount >= 0)
00474 return (int)rowcount;
00475
00476 return -1;
00477 }
00478
00479 struct update2_prepare_struct {
00480 const char *database;
00481 const char *table;
00482 va_list ap;
00483 };
00484
00485 static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
00486 {
00487 int res, x = 1, first = 1;
00488 struct update2_prepare_struct *ups = data;
00489 const char *newparam, *newval;
00490 struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
00491 SQLHSTMT stmt;
00492 va_list ap;
00493 struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
00494 struct odbc_cache_columns *column;
00495
00496 if (!sql) {
00497 if (tableptr) {
00498 ast_odbc_release_table(tableptr);
00499 }
00500 return NULL;
00501 }
00502
00503 if (!tableptr) {
00504 ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", ups->table, ups->database);
00505 return NULL;
00506 }
00507
00508 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00509 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00510 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00511 ast_odbc_release_table(tableptr);
00512 return NULL;
00513 }
00514
00515 ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
00516
00517
00518 va_copy(ap, ups->ap);
00519
00520 while ((newparam = va_arg(ap, const char *))) {
00521 newval = va_arg(ap, const char *);
00522 }
00523
00524 while ((newparam = va_arg(ap, const char *))) {
00525 newval = va_arg(ap, const char *);
00526 if ((column = ast_odbc_find_column(tableptr, newparam))) {
00527 ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam);
00528 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00529 first = 0;
00530 } else {
00531 ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database);
00532 }
00533 }
00534 va_end(ap);
00535
00536
00537 va_copy(ap, ups->ap);
00538 ast_str_append(&sql, 0, "WHERE");
00539 first = 1;
00540
00541 while ((newparam = va_arg(ap, const char *))) {
00542 newval = va_arg(ap, const char *);
00543 if (!(column = ast_odbc_find_column(tableptr, newparam))) {
00544 ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", newparam, ups->table, ups->database);
00545 ast_odbc_release_table(tableptr);
00546 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00547 return NULL;
00548 }
00549 ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam);
00550 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00551 first = 0;
00552 }
00553 va_end(ap);
00554
00555
00556 ast_odbc_release_table(tableptr);
00557
00558 res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
00559 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00560 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
00561 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00562 return NULL;
00563 }
00564
00565 return stmt;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 static int update2_odbc(const char *database, const char *table, va_list ap)
00583 {
00584 struct odbc_obj *obj;
00585 SQLHSTMT stmt;
00586 struct update2_prepare_struct ups = { .database = database, .table = table, };
00587 struct ast_str *sql;
00588 int res;
00589 SQLLEN rowcount = 0;
00590
00591 va_copy(ups.ap, ap);
00592
00593 if (!(obj = ast_odbc_request_obj(database, 0))) {
00594 return -1;
00595 }
00596
00597 if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
00598 ast_odbc_release_obj(obj);
00599 return -1;
00600 }
00601
00602 res = SQLRowCount(stmt, &rowcount);
00603 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00604 ast_odbc_release_obj(obj);
00605
00606 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00607
00608 sql = ast_str_thread_get(&sql_buf, 16);
00609 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
00610 return -1;
00611 }
00612
00613 if (rowcount >= 0) {
00614 return (int)rowcount;
00615 }
00616
00617 return -1;
00618 }
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 static int store_odbc(const char *database, const char *table, va_list ap)
00634 {
00635 struct odbc_obj *obj;
00636 SQLHSTMT stmt;
00637 char sql[256];
00638 char keys[256];
00639 char vals[256];
00640 SQLLEN rowcount=0;
00641 const char *newparam, *newval;
00642 int res;
00643 va_list aq;
00644 struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
00645
00646 va_copy(cps.ap, ap);
00647 va_copy(aq, ap);
00648
00649 if (!table)
00650 return -1;
00651
00652 obj = ast_odbc_request_obj(database, 0);
00653 if (!obj)
00654 return -1;
00655
00656 newparam = va_arg(aq, const char *);
00657 if (!newparam) {
00658 ast_odbc_release_obj(obj);
00659 return -1;
00660 }
00661 newval = va_arg(aq, const char *);
00662 snprintf(keys, sizeof(keys), "%s", newparam);
00663 ast_copy_string(vals, "?", sizeof(vals));
00664 while ((newparam = va_arg(aq, const char *))) {
00665 snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
00666 snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
00667 newval = va_arg(aq, const char *);
00668 }
00669 va_end(aq);
00670 snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
00671
00672 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00673
00674 if (!stmt) {
00675 ast_odbc_release_obj(obj);
00676 return -1;
00677 }
00678
00679 res = SQLRowCount(stmt, &rowcount);
00680 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00681 ast_odbc_release_obj(obj);
00682
00683 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00684 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00685 return -1;
00686 }
00687
00688 if (rowcount >= 0)
00689 return (int)rowcount;
00690
00691 return -1;
00692 }
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
00710 {
00711 struct odbc_obj *obj;
00712 SQLHSTMT stmt;
00713 char sql[256];
00714 SQLLEN rowcount=0;
00715 const char *newparam, *newval;
00716 int res;
00717 va_list aq;
00718 struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00719
00720 va_copy(cps.ap, ap);
00721 va_copy(aq, ap);
00722
00723 if (!table)
00724 return -1;
00725
00726 obj = ast_odbc_request_obj(database, 0);
00727 if (!obj)
00728 return -1;
00729
00730 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
00731 while((newparam = va_arg(aq, const char *))) {
00732 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
00733 newval = va_arg(aq, const char *);
00734 }
00735 va_end(aq);
00736 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
00737
00738 stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00739
00740 if (!stmt) {
00741 ast_odbc_release_obj(obj);
00742 return -1;
00743 }
00744
00745 res = SQLRowCount(stmt, &rowcount);
00746 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00747 ast_odbc_release_obj(obj);
00748
00749 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00750 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00751 return -1;
00752 }
00753
00754 if (rowcount >= 0)
00755 return (int)rowcount;
00756
00757 return -1;
00758 }
00759
00760
00761 struct config_odbc_obj {
00762 char *sql;
00763 unsigned long cat_metric;
00764 char category[128];
00765 char var_name[128];
00766 char var_val[1024];
00767 SQLLEN err;
00768 };
00769
00770 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
00771 {
00772 struct config_odbc_obj *q = data;
00773 SQLHSTMT sth;
00774 int res;
00775
00776 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00777 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00778 ast_verb(4, "Failure in AllocStatement %d\n", res);
00779 return NULL;
00780 }
00781
00782 res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00783 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00784 ast_verb(4, "Error in PREPARE %d\n", res);
00785 SQLFreeHandle(SQL_HANDLE_STMT, sth);
00786 return NULL;
00787 }
00788
00789 SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
00790 SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
00791 SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
00792 SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
00793
00794 return sth;
00795 }
00796
00797 static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
00798 {
00799 struct ast_variable *new_v;
00800 struct ast_category *cur_cat;
00801 int res = 0;
00802 struct odbc_obj *obj;
00803 char sqlbuf[1024] = "";
00804 char *sql = sqlbuf;
00805 size_t sqlleft = sizeof(sqlbuf);
00806 unsigned int last_cat_metric = 0;
00807 SQLSMALLINT rowcount = 0;
00808 SQLHSTMT stmt;
00809 char last[128] = "";
00810 struct config_odbc_obj q;
00811 struct ast_flags loader_flags = { 0 };
00812
00813 memset(&q, 0, sizeof(q));
00814
00815 if (!file || !strcmp (file, "res_config_odbc.conf"))
00816 return NULL;
00817
00818 obj = ast_odbc_request_obj(database, 0);
00819 if (!obj)
00820 return NULL;
00821
00822 ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
00823 ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
00824 ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00825 q.sql = sqlbuf;
00826
00827 stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
00828
00829 if (!stmt) {
00830 ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
00831 ast_odbc_release_obj(obj);
00832 return NULL;
00833 }
00834
00835 res = SQLNumResultCols(stmt, &rowcount);
00836
00837 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00838 ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
00839 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00840 ast_odbc_release_obj(obj);
00841 return NULL;
00842 }
00843
00844 if (!rowcount) {
00845 ast_log(LOG_NOTICE, "found nothing\n");
00846 ast_odbc_release_obj(obj);
00847 return cfg;
00848 }
00849
00850 cur_cat = ast_config_get_current_category(cfg);
00851
00852 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
00853 if (!strcmp (q.var_name, "#include")) {
00854 if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
00855 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00856 ast_odbc_release_obj(obj);
00857 return NULL;
00858 }
00859 continue;
00860 }
00861 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
00862 cur_cat = ast_category_new(q.category, "", 99999);
00863 if (!cur_cat) {
00864 ast_log(LOG_WARNING, "Out of memory!\n");
00865 break;
00866 }
00867 strcpy(last, q.category);
00868 last_cat_metric = q.cat_metric;
00869 ast_category_append(cfg, cur_cat);
00870 }
00871
00872 new_v = ast_variable_new(q.var_name, q.var_val, "");
00873 ast_variable_append(cur_cat, new_v);
00874 }
00875
00876 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00877 ast_odbc_release_obj(obj);
00878 return cfg;
00879 }
00880
00881 #define warn_length(col, size) ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is not long enough to contain realtime data (needs %d)\n", table, database, col->name, size)
00882 #define warn_type(col, type) ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is of the incorrect type (%d) to contain the required realtime data\n", table, database, col->name, col->type)
00883
00884 static int require_odbc(const char *database, const char *table, va_list ap)
00885 {
00886 struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
00887 struct odbc_cache_columns *col;
00888 char *elm;
00889 int type, size;
00890
00891 if (!tableptr) {
00892 return -1;
00893 }
00894
00895 while ((elm = va_arg(ap, char *))) {
00896 type = va_arg(ap, require_type);
00897 size = va_arg(ap, int);
00898
00899 AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
00900 if (strcmp(col->name, elm) == 0) {
00901
00902 switch (col->type) {
00903 case SQL_CHAR:
00904 case SQL_VARCHAR:
00905 case SQL_LONGVARCHAR:
00906 #ifdef HAVE_ODBC_WCHAR
00907 case SQL_WCHAR:
00908 case SQL_WVARCHAR:
00909 case SQL_WLONGVARCHAR:
00910 #endif
00911 case SQL_BINARY:
00912 case SQL_VARBINARY:
00913 case SQL_LONGVARBINARY:
00914 case SQL_GUID:
00915 #define CHECK_SIZE(n) \
00916 if (col->size < n) { \
00917 warn_length(col, n); \
00918 } \
00919 break;
00920 switch (type) {
00921 case RQ_UINTEGER1: CHECK_SIZE(3)
00922 case RQ_INTEGER1: CHECK_SIZE(4)
00923 case RQ_UINTEGER2: CHECK_SIZE(5)
00924 case RQ_INTEGER2: CHECK_SIZE(6)
00925 case RQ_UINTEGER3:
00926 case RQ_INTEGER3: CHECK_SIZE(8)
00927 case RQ_DATE:
00928 case RQ_UINTEGER4: CHECK_SIZE(10)
00929 case RQ_INTEGER4: CHECK_SIZE(11)
00930 case RQ_DATETIME:
00931 case RQ_UINTEGER8: CHECK_SIZE(19)
00932 case RQ_INTEGER8: CHECK_SIZE(20)
00933 case RQ_FLOAT:
00934 case RQ_CHAR: CHECK_SIZE(size)
00935 }
00936 #undef CHECK_SIZE
00937 break;
00938 case SQL_TYPE_DATE:
00939 if (type != RQ_DATE) {
00940 warn_type(col, type);
00941 }
00942 break;
00943 case SQL_TYPE_TIMESTAMP:
00944 case SQL_TIMESTAMP:
00945 if (type != RQ_DATE && type != RQ_DATETIME) {
00946 warn_type(col, type);
00947 }
00948 break;
00949 case SQL_BIT:
00950 warn_length(col, size);
00951 break;
00952 #define WARN_TYPE_OR_LENGTH(n) \
00953 if (!ast_rq_is_int(type)) { \
00954 warn_type(col, type); \
00955 } else { \
00956 warn_length(col, n); \
00957 }
00958 case SQL_TINYINT:
00959 if (type != RQ_UINTEGER1) {
00960 WARN_TYPE_OR_LENGTH(size)
00961 }
00962 break;
00963 case SQL_C_STINYINT:
00964 if (type != RQ_INTEGER1) {
00965 WARN_TYPE_OR_LENGTH(size)
00966 }
00967 break;
00968 case SQL_C_USHORT:
00969 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
00970 WARN_TYPE_OR_LENGTH(size)
00971 }
00972 break;
00973 case SQL_SMALLINT:
00974 case SQL_C_SSHORT:
00975 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
00976 WARN_TYPE_OR_LENGTH(size)
00977 }
00978 break;
00979 case SQL_C_ULONG:
00980 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
00981 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
00982 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
00983 type != RQ_INTEGER4) {
00984 WARN_TYPE_OR_LENGTH(size)
00985 }
00986 break;
00987 case SQL_INTEGER:
00988 case SQL_C_SLONG:
00989 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
00990 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
00991 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
00992 type != RQ_INTEGER4) {
00993 WARN_TYPE_OR_LENGTH(size)
00994 }
00995 break;
00996 case SQL_C_UBIGINT:
00997 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
00998 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
00999 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01000 type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
01001 type != RQ_INTEGER8) {
01002 WARN_TYPE_OR_LENGTH(size)
01003 }
01004 break;
01005 case SQL_BIGINT:
01006 case SQL_C_SBIGINT:
01007 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
01008 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
01009 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
01010 type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
01011 type != RQ_INTEGER8) {
01012 WARN_TYPE_OR_LENGTH(size)
01013 }
01014 break;
01015 #undef WARN_TYPE_OR_LENGTH
01016 case SQL_NUMERIC:
01017 case SQL_DECIMAL:
01018 case SQL_FLOAT:
01019 case SQL_REAL:
01020 case SQL_DOUBLE:
01021 if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
01022 warn_type(col, type);
01023 }
01024 break;
01025 default:
01026 ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm);
01027 }
01028 break;
01029 }
01030 }
01031 if (!col) {
01032 ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
01033 }
01034 }
01035 va_end(ap);
01036 AST_RWLIST_UNLOCK(&tableptr->columns);
01037 return 0;
01038 }
01039 #undef warn_length
01040 #undef warn_type
01041
01042 static struct ast_config_engine odbc_engine = {
01043 .name = "odbc",
01044 .load_func = config_odbc,
01045 .realtime_func = realtime_odbc,
01046 .realtime_multi_func = realtime_multi_odbc,
01047 .store_func = store_odbc,
01048 .destroy_func = destroy_odbc,
01049 .update_func = update_odbc,
01050 .update2_func = update2_odbc,
01051 .require_func = require_odbc,
01052 .unload_func = ast_odbc_clear_cache,
01053 };
01054
01055 static int unload_module (void)
01056 {
01057 ast_config_engine_deregister(&odbc_engine);
01058
01059 ast_verb(1, "res_config_odbc unloaded.\n");
01060 return 0;
01061 }
01062
01063 static int load_module (void)
01064 {
01065 ast_config_engine_register(&odbc_engine);
01066 ast_verb(1, "res_config_odbc loaded.\n");
01067 return 0;
01068 }
01069
01070 static int reload_module(void)
01071 {
01072 return 0;
01073 }
01074
01075 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Realtime ODBC configuration",
01076 .load = load_module,
01077 .unload = unload_module,
01078 .reload = reload_module,
01079 );