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