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