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