ODBC lookups. More...
#include "asterisk.h"#include "asterisk/module.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/config.h"#include "asterisk/res_odbc.h"#include "asterisk/app.h"#include "asterisk/cli.h"#include "asterisk/strings.h"
Go to the source code of this file.
Data Structures | |
| struct | acf_odbc_query |
| struct | odbc_datastore |
| struct | odbc_datastore_row |
| struct | queries |
Enumerations | |
| enum | { OPT_ESCAPECOMMAS = (1 << 0), OPT_MULTIROW = (1 << 1) } |
Functions | |
| static void | __init_coldata_buf (void) |
| static void | __init_colnames_buf (void) |
| static void | __init_sql2_buf (void) |
| static void | __init_sql_buf (void) |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | acf_escape (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| static int | acf_fetch (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| static int | acf_odbc_read (struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len) |
| static int | acf_odbc_write (struct ast_channel *chan, const char *cmd, char *s, const char *value) |
| static char * | cli_odbc_read (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | cli_odbc_write (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | exec_odbcfinish (struct ast_channel *chan, void *data) |
| static int | free_acf_query (struct acf_odbc_query *query) |
| static SQLHSTMT | generic_execute (struct odbc_obj *obj, void *data) |
| static int | init_acf_query (struct ast_config *cfg, char *catg, struct acf_odbc_query **query) |
| static int | load_module (void) |
| static void | odbc_datastore_free (void *data) |
| static int | reload (void) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ODBC lookups" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
| static char * | app_odbcfinish = "ODBCFinish" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_func_odbc [] |
| static struct ast_threadstorage | coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , } |
| static struct ast_threadstorage | colnames_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_colnames_buf , .custom_init = NULL , } |
| static char * | config = "func_odbc.conf" |
| static struct ast_custom_function | escape_function |
| static struct ast_custom_function | fetch_function |
| struct ast_datastore_info | odbc_info |
| enum { ... } | odbc_option_flags |
| static int | resultcount = 0 |
| static struct ast_threadstorage | sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , } |
| static struct ast_threadstorage | sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , } |
ODBC lookups.
Definition in file func_odbc.c.
| anonymous enum |
Definition at line 102 of file func_odbc.c.
00102 { 00103 OPT_ESCAPECOMMAS = (1 << 0), 00104 OPT_MULTIROW = (1 << 1), 00105 } odbc_option_flags;
| static void __init_coldata_buf | ( | void | ) | [static] |
Definition at line 144 of file func_odbc.c.
| static void __init_colnames_buf | ( | void | ) | [static] |
Definition at line 145 of file func_odbc.c.
| static void __init_sql2_buf | ( | void | ) | [static] |
Definition at line 143 of file func_odbc.c.
| static void __init_sql_buf | ( | void | ) | [static] |
Definition at line 142 of file func_odbc.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1444 of file func_odbc.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1444 of file func_odbc.c.
| static int acf_escape | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 677 of file func_odbc.c.
| static int acf_fetch | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 699 of file func_odbc.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_copy_string(), ast_datastore_free(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, odbc_datastore_row::data, ast_datastore::data, acf_odbc_query::list, odbc_datastore::names, odbc_info, and pbx_builtin_setvar_helper().
00700 { 00701 struct ast_datastore *store; 00702 struct odbc_datastore *resultset; 00703 struct odbc_datastore_row *row; 00704 store = ast_channel_datastore_find(chan, &odbc_info, data); 00705 if (!store) { 00706 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE"); 00707 return -1; 00708 } 00709 resultset = store->data; 00710 AST_LIST_LOCK(resultset); 00711 row = AST_LIST_REMOVE_HEAD(resultset, list); 00712 AST_LIST_UNLOCK(resultset); 00713 if (!row) { 00714 /* Cleanup datastore */ 00715 ast_channel_datastore_remove(chan, store); 00716 ast_datastore_free(store); 00717 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE"); 00718 return -1; 00719 } 00720 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names); 00721 ast_copy_string(buf, row->data, len); 00722 ast_free(row); 00723 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS"); 00724 return 0; 00725 }
| static int acf_odbc_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | s, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 375 of file func_odbc.c.
References acf_odbc_query::acf, AST_APP_ARG, ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_alloc, ast_channel_datastore_add(), ast_channel_free(), ast_copy_string(), ast_datastore_alloc, ast_debug, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_ast_str_SQLGetData(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj(), ast_realloc, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_append_escapecommas(), ast_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_strlen(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strlen_zero(), ast_test_flag, ast_verb, coldata_buf, colnames_buf, ast_datastore::data, dsn, generic_execute(), acf_odbc_query::list, LOG_ERROR, LOG_WARNING, ast_custom_function::name, odbc_datastore_free(), odbc_info, OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), acf_odbc_query::readhandle, resultcount, acf_odbc_query::rowlimit, sql_buf, acf_odbc_query::sql_read, and status.
Referenced by init_acf_query().
00376 { 00377 struct odbc_obj *obj = NULL; 00378 struct acf_odbc_query *query; 00379 char varname[15], rowcount[12] = "-1"; 00380 struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16); 00381 int res, x, y, buflen = 0, escapecommas, rowlimit = 1, dsn, bogus_chan = 0; 00382 AST_DECLARE_APP_ARGS(args, 00383 AST_APP_ARG(field)[100]; 00384 ); 00385 SQLHSTMT stmt = NULL; 00386 SQLSMALLINT colcount=0; 00387 SQLLEN indicator; 00388 SQLSMALLINT collength; 00389 struct odbc_datastore *resultset = NULL; 00390 struct odbc_datastore_row *row = NULL; 00391 struct ast_str *sql = ast_str_thread_get(&sql_buf, 16); 00392 const char *status = "FAILURE"; 00393 00394 if (!sql) { 00395 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); 00396 return -1; 00397 } 00398 00399 ast_str_reset(colnames); 00400 00401 AST_RWLIST_RDLOCK(&queries); 00402 AST_RWLIST_TRAVERSE(&queries, query, list) { 00403 if (!strcmp(query->acf->name, cmd)) { 00404 break; 00405 } 00406 } 00407 00408 if (!query) { 00409 ast_log(LOG_ERROR, "No such function '%s'\n", cmd); 00410 AST_RWLIST_UNLOCK(&queries); 00411 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00412 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); 00413 return -1; 00414 } 00415 00416 if (!chan) { 00417 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) { 00418 bogus_chan = 1; 00419 } 00420 } 00421 00422 if (chan) { 00423 ast_autoservice_start(chan); 00424 } 00425 00426 AST_STANDARD_APP_ARGS(args, s); 00427 for (x = 0; x < args.argc; x++) { 00428 snprintf(varname, sizeof(varname), "ARG%d", x + 1); 00429 pbx_builtin_pushvar_helper(chan, varname, args.field[x]); 00430 } 00431 00432 ast_str_substitute_variables(&sql, 0, chan, query->sql_read); 00433 00434 /* Restore prior values */ 00435 for (x = 0; x < args.argc; x++) { 00436 snprintf(varname, sizeof(varname), "ARG%d", x + 1); 00437 pbx_builtin_setvar_helper(chan, varname, NULL); 00438 } 00439 00440 /* Save these flags, so we can release the lock */ 00441 escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS); 00442 if (ast_test_flag(query, OPT_MULTIROW)) { 00443 resultset = ast_calloc(1, sizeof(*resultset)); 00444 AST_LIST_HEAD_INIT(resultset); 00445 if (query->rowlimit) { 00446 rowlimit = query->rowlimit; 00447 } else { 00448 rowlimit = INT_MAX; 00449 } 00450 } 00451 AST_RWLIST_UNLOCK(&queries); 00452 00453 for (dsn = 0; dsn < 5; dsn++) { 00454 if (!ast_strlen_zero(query->readhandle[dsn])) { 00455 obj = ast_odbc_request_obj(query->readhandle[dsn], 0); 00456 if (obj) { 00457 stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)); 00458 } 00459 } 00460 if (stmt) { 00461 break; 00462 } 00463 } 00464 00465 if (!stmt) { 00466 ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql)); 00467 if (obj) { 00468 ast_odbc_release_obj(obj); 00469 obj = NULL; 00470 } 00471 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00472 if (chan) { 00473 ast_autoservice_stop(chan); 00474 } 00475 if (bogus_chan) { 00476 ast_channel_free(chan); 00477 } 00478 return -1; 00479 } 00480 00481 res = SQLNumResultCols(stmt, &colcount); 00482 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00483 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); 00484 SQLCloseCursor(stmt); 00485 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00486 ast_odbc_release_obj(obj); 00487 obj = NULL; 00488 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00489 if (chan) { 00490 ast_autoservice_stop(chan); 00491 } 00492 if (bogus_chan) { 00493 ast_channel_free(chan); 00494 } 00495 return -1; 00496 } 00497 00498 res = SQLFetch(stmt); 00499 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00500 int res1 = -1; 00501 if (res == SQL_NO_DATA) { 00502 ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql)); 00503 res1 = 0; 00504 buf[0] = '\0'; 00505 ast_copy_string(rowcount, "0", sizeof(rowcount)); 00506 status = "NODATA"; 00507 } else { 00508 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql)); 00509 status = "FETCHERROR"; 00510 } 00511 SQLCloseCursor(stmt); 00512 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00513 ast_odbc_release_obj(obj); 00514 obj = NULL; 00515 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00516 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); 00517 if (chan) 00518 ast_autoservice_stop(chan); 00519 if (bogus_chan) 00520 ast_channel_free(chan); 00521 return res1; 00522 } 00523 00524 status = "SUCCESS"; 00525 00526 for (y = 0; y < rowlimit; y++) { 00527 buf[0] = '\0'; 00528 for (x = 0; x < colcount; x++) { 00529 int i; 00530 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16); 00531 char *ptrcoldata; 00532 00533 if (y == 0) { 00534 char colname[256]; 00535 SQLULEN maxcol; 00536 00537 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL); 00538 ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x); 00539 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { 00540 snprintf(colname, sizeof(colname), "field%d", x); 00541 } 00542 00543 ast_str_make_space(&coldata, maxcol + 1); 00544 00545 if (ast_str_strlen(colnames)) { 00546 ast_str_append(&colnames, 0, ","); 00547 } 00548 ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname)); 00549 00550 if (resultset) { 00551 void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1); 00552 if (!tmp) { 00553 ast_log(LOG_ERROR, "No space for a new resultset?\n"); 00554 ast_free(resultset); 00555 SQLCloseCursor(stmt); 00556 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00557 ast_odbc_release_obj(obj); 00558 obj = NULL; 00559 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00560 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); 00561 if (chan) 00562 ast_autoservice_stop(chan); 00563 if (bogus_chan) 00564 ast_channel_free(chan); 00565 return -1; 00566 } 00567 resultset = tmp; 00568 strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames)); 00569 } 00570 } 00571 00572 buflen = strlen(buf); 00573 res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator); 00574 if (indicator == SQL_NULL_DATA) { 00575 ast_debug(3, "Got NULL data\n"); 00576 ast_str_reset(coldata); 00577 res = SQL_SUCCESS; 00578 } 00579 00580 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00581 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql)); 00582 y = -1; 00583 buf[0] = '\0'; 00584 goto end_acf_read; 00585 } 00586 00587 ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata)); 00588 00589 if (x) { 00590 buf[buflen++] = ','; 00591 } 00592 00593 /* Copy data, encoding '\' and ',' for the argument parser */ 00594 ptrcoldata = ast_str_buffer(coldata); 00595 for (i = 0; i < ast_str_strlen(coldata); i++) { 00596 if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) { 00597 buf[buflen++] = '\\'; 00598 } 00599 buf[buflen++] = ptrcoldata[i]; 00600 00601 if (buflen >= len - 2) { 00602 break; 00603 } 00604 00605 if (ptrcoldata[i] == '\0') { 00606 break; 00607 } 00608 } 00609 00610 buf[buflen] = '\0'; 00611 ast_debug(2, "buf is now set to '%s'\n", buf); 00612 } 00613 ast_debug(2, "buf is now set to '%s'\n", buf); 00614 00615 if (resultset) { 00616 row = ast_calloc(1, sizeof(*row) + buflen + 1); 00617 if (!row) { 00618 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n"); 00619 status = "MEMERROR"; 00620 goto end_acf_read; 00621 } 00622 strcpy((char *)row + sizeof(*row), buf); 00623 AST_LIST_INSERT_TAIL(resultset, row, list); 00624 00625 /* Get next row */ 00626 res = SQLFetch(stmt); 00627 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00628 if (res != SQL_NO_DATA) { 00629 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql)); 00630 } 00631 /* Number of rows in the resultset */ 00632 y++; 00633 break; 00634 } 00635 } 00636 } 00637 00638 end_acf_read: 00639 snprintf(rowcount, sizeof(rowcount), "%d", y); 00640 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00641 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); 00642 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames)); 00643 if (resultset) { 00644 int uid; 00645 struct ast_datastore *odbc_store; 00646 uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1; 00647 snprintf(buf, len, "%d", uid); 00648 odbc_store = ast_datastore_alloc(&odbc_info, buf); 00649 if (!odbc_store) { 00650 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n"); 00651 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); 00652 odbc_datastore_free(resultset); 00653 SQLCloseCursor(stmt); 00654 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00655 ast_odbc_release_obj(obj); 00656 obj = NULL; 00657 if (chan) 00658 ast_autoservice_stop(chan); 00659 if (bogus_chan) 00660 ast_channel_free(chan); 00661 return -1; 00662 } 00663 odbc_store->data = resultset; 00664 ast_channel_datastore_add(chan, odbc_store); 00665 } 00666 SQLCloseCursor(stmt); 00667 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00668 ast_odbc_release_obj(obj); 00669 obj = NULL; 00670 if (chan) 00671 ast_autoservice_stop(chan); 00672 if (bogus_chan) 00673 ast_channel_free(chan); 00674 return 0; 00675 }
| static int acf_odbc_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | s, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 203 of file func_odbc.c.
References acf_odbc_query::acf, AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_alloc, ast_channel_free(), AST_DECLARE_APP_ARGS, ast_log(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj(), ast_odbc_retrieve_transaction_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_make_space(), ast_str_strlen(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strlen_zero(), buf, dsn, generic_execute(), acf_odbc_query::list, LOG_ERROR, LOG_WARNING, ast_custom_function::name, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), sql2_buf, sql_buf, acf_odbc_query::sql_insert, acf_odbc_query::sql_write, status, and acf_odbc_query::writehandle.
Referenced by init_acf_query().
00204 { 00205 struct odbc_obj *obj = NULL; 00206 struct acf_odbc_query *query; 00207 char *t, varname[15]; 00208 int i, dsn, bogus_chan = 0; 00209 int transactional = 0; 00210 AST_DECLARE_APP_ARGS(values, 00211 AST_APP_ARG(field)[100]; 00212 ); 00213 AST_DECLARE_APP_ARGS(args, 00214 AST_APP_ARG(field)[100]; 00215 ); 00216 SQLHSTMT stmt = NULL; 00217 SQLLEN rows=0; 00218 struct ast_str *buf = ast_str_thread_get(&sql_buf, 16); 00219 struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16); 00220 const char *status = "FAILURE"; 00221 00222 if (!buf) { 00223 return -1; 00224 } 00225 00226 AST_RWLIST_RDLOCK(&queries); 00227 AST_RWLIST_TRAVERSE(&queries, query, list) { 00228 if (!strcmp(query->acf->name, cmd)) { 00229 break; 00230 } 00231 } 00232 00233 if (!query) { 00234 ast_log(LOG_ERROR, "No such function '%s'\n", cmd); 00235 AST_RWLIST_UNLOCK(&queries); 00236 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); 00237 return -1; 00238 } 00239 00240 if (!chan) { 00241 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) 00242 bogus_chan = 1; 00243 } 00244 00245 if (chan) 00246 ast_autoservice_start(chan); 00247 00248 ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300); 00249 ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300); 00250 00251 /* Parse our arguments */ 00252 t = value ? ast_strdupa(value) : ""; 00253 00254 if (!s || !t) { 00255 ast_log(LOG_ERROR, "Out of memory\n"); 00256 AST_RWLIST_UNLOCK(&queries); 00257 if (chan) 00258 ast_autoservice_stop(chan); 00259 if (bogus_chan) { 00260 ast_channel_free(chan); 00261 } else { 00262 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); 00263 } 00264 return -1; 00265 } 00266 00267 AST_STANDARD_APP_ARGS(args, s); 00268 for (i = 0; i < args.argc; i++) { 00269 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 00270 pbx_builtin_pushvar_helper(chan, varname, args.field[i]); 00271 } 00272 00273 /* Parse values, just like arguments */ 00274 AST_STANDARD_APP_ARGS(values, t); 00275 for (i = 0; i < values.argc; i++) { 00276 snprintf(varname, sizeof(varname), "VAL%d", i + 1); 00277 pbx_builtin_pushvar_helper(chan, varname, values.field[i]); 00278 } 00279 00280 /* Additionally set the value as a whole (but push an empty string if value is NULL) */ 00281 pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : ""); 00282 00283 ast_str_substitute_variables(&buf, 0, chan, query->sql_write); 00284 ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert); 00285 00286 /* Restore prior values */ 00287 for (i = 0; i < args.argc; i++) { 00288 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 00289 pbx_builtin_setvar_helper(chan, varname, NULL); 00290 } 00291 00292 for (i = 0; i < values.argc; i++) { 00293 snprintf(varname, sizeof(varname), "VAL%d", i + 1); 00294 pbx_builtin_setvar_helper(chan, varname, NULL); 00295 } 00296 pbx_builtin_setvar_helper(chan, "VALUE", NULL); 00297 00298 /*!\note 00299 * Okay, this part is confusing. Transactions belong to a single database 00300 * handle. Therefore, when working with transactions, we CANNOT failover 00301 * to multiple DSNs. We MUST have a single handle all the way through the 00302 * transaction, or else we CANNOT enforce atomicity. 00303 */ 00304 for (dsn = 0; dsn < 5; dsn++) { 00305 if (transactional) { 00306 /* This can only happen second time through or greater. */ 00307 ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n"); 00308 } 00309 00310 if (!ast_strlen_zero(query->writehandle[dsn])) { 00311 if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) { 00312 transactional = 1; 00313 } else { 00314 obj = ast_odbc_request_obj(query->writehandle[dsn], 0); 00315 transactional = 0; 00316 } 00317 if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) { 00318 break; 00319 } 00320 } 00321 00322 if (obj && !transactional) { 00323 ast_odbc_release_obj(obj); 00324 } 00325 } 00326 00327 if (stmt && rows == 0 && ast_str_strlen(insertbuf) != 0) { 00328 SQLCloseCursor(stmt); 00329 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00330 for (dsn = 0; dsn < 5; dsn++) { 00331 if (!ast_strlen_zero(query->writehandle[dsn])) { 00332 obj = ast_odbc_request_obj(query->writehandle[dsn], 0); 00333 if (obj) { 00334 stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf)); 00335 } 00336 } 00337 if (stmt) { 00338 status = "FAILOVER"; 00339 SQLRowCount(stmt, &rows); 00340 break; 00341 } 00342 } 00343 } else if (stmt) { 00344 status = "SUCCESS"; 00345 SQLRowCount(stmt, &rows); 00346 } 00347 00348 AST_RWLIST_UNLOCK(&queries); 00349 00350 /* Output the affected rows, for all cases. In the event of failure, we 00351 * flag this as -1 rows. Note that this is different from 0 affected rows 00352 * which would be the case if we succeeded in our query, but the values did 00353 * not change. */ 00354 snprintf(varname, sizeof(varname), "%d", (int)rows); 00355 pbx_builtin_setvar_helper(chan, "ODBCROWS", varname); 00356 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); 00357 00358 if (stmt) { 00359 SQLCloseCursor(stmt); 00360 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00361 } 00362 if (obj && !transactional) { 00363 ast_odbc_release_obj(obj); 00364 obj = NULL; 00365 } 00366 00367 if (chan) 00368 ast_autoservice_stop(chan); 00369 if (bogus_chan) 00370 ast_channel_free(chan); 00371 00372 return 0; 00373 }
| static char* cli_odbc_read | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 978 of file func_odbc.c.
References acf_odbc_query::acf, ast_cli_args::argc, ast_cli_args::argv, AST_APP_ARG, ast_channel_alloc, ast_channel_free(), ast_cli(), ast_debug, AST_DECLARE_APP_ARGS, ast_odbc_ast_str_SQLGetData(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_make_space(), ast_str_set(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strdup, ast_strlen_zero(), chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, coldata_buf, ast_cli_entry::command, dsn, ast_cli_args::fd, generic_execute(), acf_odbc_query::list, ast_cli_args::n, ast_custom_function::name, pbx_builtin_pushvar_helper(), ast_cli_args::pos, acf_odbc_query::readhandle, sql_buf, acf_odbc_query::sql_read, ast_cli_entry::usage, and ast_cli_args::word.
00979 { 00980 AST_DECLARE_APP_ARGS(args, 00981 AST_APP_ARG(field)[100]; 00982 ); 00983 struct ast_str *sql; 00984 char *char_args, varname[10]; 00985 struct acf_odbc_query *query; 00986 struct ast_channel *chan; 00987 int i; 00988 00989 switch (cmd) { 00990 case CLI_INIT: 00991 e->command = "odbc read"; 00992 e->usage = 00993 "Usage: odbc read <name> <args> [exec]\n" 00994 " Evaluates the SQL provided in the ODBC function <name>, and\n" 00995 " optionally executes the function. This function is intended for\n" 00996 " testing purposes. Remember to quote arguments containing spaces.\n"; 00997 return NULL; 00998 case CLI_GENERATE: 00999 if (a->pos == 2) { 01000 int wordlen = strlen(a->word), which = 0; 01001 /* Complete function name */ 01002 AST_RWLIST_RDLOCK(&queries); 01003 AST_RWLIST_TRAVERSE(&queries, query, list) { 01004 if (!strncasecmp(query->acf->name, a->word, wordlen)) { 01005 if (++which > a->n) { 01006 char *res = ast_strdup(query->acf->name); 01007 AST_RWLIST_UNLOCK(&queries); 01008 return res; 01009 } 01010 } 01011 } 01012 AST_RWLIST_UNLOCK(&queries); 01013 return NULL; 01014 } else if (a->pos == 4) { 01015 return a->n == 0 ? ast_strdup("exec") : NULL; 01016 } else { 01017 return NULL; 01018 } 01019 } 01020 01021 if (a->argc < 4 || a->argc > 5) { 01022 return CLI_SHOWUSAGE; 01023 } 01024 01025 sql = ast_str_thread_get(&sql_buf, 16); 01026 if (!sql) { 01027 return CLI_FAILURE; 01028 } 01029 01030 AST_RWLIST_RDLOCK(&queries); 01031 AST_RWLIST_TRAVERSE(&queries, query, list) { 01032 if (!strcmp(query->acf->name, a->argv[2])) { 01033 break; 01034 } 01035 } 01036 01037 if (!query) { 01038 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]); 01039 AST_RWLIST_UNLOCK(&queries); 01040 return CLI_SHOWUSAGE; 01041 } 01042 01043 if (ast_strlen_zero(query->sql_read)) { 01044 ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]); 01045 AST_RWLIST_UNLOCK(&queries); 01046 return CLI_SUCCESS; 01047 } 01048 01049 ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300); 01050 01051 /* Evaluate function */ 01052 char_args = ast_strdupa(a->argv[3]); 01053 01054 chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"); 01055 01056 AST_STANDARD_APP_ARGS(args, char_args); 01057 for (i = 0; i < args.argc; i++) { 01058 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 01059 pbx_builtin_pushvar_helper(chan, varname, args.field[i]); 01060 } 01061 01062 ast_str_substitute_variables(&sql, 0, chan, query->sql_read); 01063 ast_channel_free(chan); 01064 01065 if (a->argc == 5 && !strcmp(a->argv[4], "exec")) { 01066 /* Execute the query */ 01067 struct odbc_obj *obj = NULL; 01068 int dsn, executed = 0; 01069 SQLHSTMT stmt; 01070 int rows = 0, res, x; 01071 SQLSMALLINT colcount = 0, collength; 01072 SQLLEN indicator; 01073 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16); 01074 char colname[256]; 01075 SQLULEN maxcol; 01076 01077 for (dsn = 0; dsn < 5; dsn++) { 01078 if (ast_strlen_zero(query->readhandle[dsn])) { 01079 continue; 01080 } 01081 ast_debug(1, "Found handle %s\n", query->readhandle[dsn]); 01082 if (!(obj = ast_odbc_request_obj(query->readhandle[dsn], 0))) { 01083 continue; 01084 } 01085 01086 ast_debug(1, "Got obj\n"); 01087 if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { 01088 ast_odbc_release_obj(obj); 01089 obj = NULL; 01090 continue; 01091 } 01092 01093 executed = 1; 01094 01095 res = SQLNumResultCols(stmt, &colcount); 01096 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01097 ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); 01098 SQLCloseCursor(stmt); 01099 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 01100 ast_odbc_release_obj(obj); 01101 obj = NULL; 01102 AST_RWLIST_UNLOCK(&queries); 01103 return CLI_SUCCESS; 01104 } 01105 01106 res = SQLFetch(stmt); 01107 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01108 SQLCloseCursor(stmt); 01109 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01110 ast_odbc_release_obj(obj); 01111 obj = NULL; 01112 if (res == SQL_NO_DATA) { 01113 ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql)); 01114 break; 01115 } else { 01116 ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql)); 01117 } 01118 AST_RWLIST_UNLOCK(&queries); 01119 return CLI_SUCCESS; 01120 } 01121 for (;;) { 01122 for (x = 0; x < colcount; x++) { 01123 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL); 01124 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { 01125 snprintf(colname, sizeof(colname), "field%d", x); 01126 } 01127 01128 res = ast_odbc_ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator); 01129 if (indicator == SQL_NULL_DATA) { 01130 ast_str_set(&coldata, 0, "(nil)"); 01131 res = SQL_SUCCESS; 01132 } 01133 01134 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01135 ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql)); 01136 SQLCloseCursor(stmt); 01137 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01138 ast_odbc_release_obj(obj); 01139 obj = NULL; 01140 AST_RWLIST_UNLOCK(&queries); 01141 return CLI_SUCCESS; 01142 } 01143 01144 ast_cli(a->fd, "%-20.20s %s\n", colname, ast_str_buffer(coldata)); 01145 } 01146 rows++; 01147 01148 /* Get next row */ 01149 res = SQLFetch(stmt); 01150 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01151 break; 01152 } 01153 ast_cli(a->fd, "%-20.20s %s\n", "----------", "----------"); 01154 } 01155 SQLCloseCursor(stmt); 01156 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01157 ast_odbc_release_obj(obj); 01158 obj = NULL; 01159 ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn, query->readhandle[dsn]); 01160 break; 01161 } 01162 if (obj) { 01163 ast_odbc_release_obj(obj); 01164 obj = NULL; 01165 } 01166 01167 if (!executed) { 01168 ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql)); 01169 } 01170 } else { /* No execution, just print out the resulting SQL */ 01171 ast_cli(a->fd, "%s\n", ast_str_buffer(sql)); 01172 } 01173 AST_RWLIST_UNLOCK(&queries); 01174 return CLI_SUCCESS; 01175 }
| static char* cli_odbc_write | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1177 of file func_odbc.c.
References acf_odbc_query::acf, ast_cli_args::argc, ast_cli_args::argv, AST_APP_ARG, ast_channel_alloc, ast_channel_free(), ast_cli(), ast_debug, AST_DECLARE_APP_ARGS, ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_make_space(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strdup, ast_strlen_zero(), chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dsn, ast_cli_args::fd, generic_execute(), acf_odbc_query::list, ast_cli_args::n, ast_custom_function::name, pbx_builtin_pushvar_helper(), ast_cli_args::pos, S_OR, sql_buf, acf_odbc_query::sql_write, ast_cli_entry::usage, ast_cli_args::word, and acf_odbc_query::writehandle.
01178 { 01179 AST_DECLARE_APP_ARGS(values, 01180 AST_APP_ARG(field)[100]; 01181 ); 01182 AST_DECLARE_APP_ARGS(args, 01183 AST_APP_ARG(field)[100]; 01184 ); 01185 struct ast_str *sql; 01186 char *char_args, *char_values, varname[10]; 01187 struct acf_odbc_query *query; 01188 struct ast_channel *chan; 01189 int i; 01190 01191 switch (cmd) { 01192 case CLI_INIT: 01193 e->command = "odbc write"; 01194 e->usage = 01195 "Usage: odbc write <name> <args> <value> [exec]\n" 01196 " Evaluates the SQL provided in the ODBC function <name>, and\n" 01197 " optionally executes the function. This function is intended for\n" 01198 " testing purposes. Remember to quote arguments containing spaces.\n"; 01199 return NULL; 01200 case CLI_GENERATE: 01201 if (a->pos == 2) { 01202 int wordlen = strlen(a->word), which = 0; 01203 /* Complete function name */ 01204 AST_RWLIST_RDLOCK(&queries); 01205 AST_RWLIST_TRAVERSE(&queries, query, list) { 01206 if (!strncasecmp(query->acf->name, a->word, wordlen)) { 01207 if (++which > a->n) { 01208 char *res = ast_strdup(query->acf->name); 01209 AST_RWLIST_UNLOCK(&queries); 01210 return res; 01211 } 01212 } 01213 } 01214 AST_RWLIST_UNLOCK(&queries); 01215 return NULL; 01216 } else if (a->pos == 5) { 01217 return a->n == 0 ? ast_strdup("exec") : NULL; 01218 } else { 01219 return NULL; 01220 } 01221 } 01222 01223 if (a->argc < 5 || a->argc > 6) { 01224 return CLI_SHOWUSAGE; 01225 } 01226 01227 sql = ast_str_thread_get(&sql_buf, 16); 01228 if (!sql) { 01229 return CLI_FAILURE; 01230 } 01231 01232 AST_RWLIST_RDLOCK(&queries); 01233 AST_RWLIST_TRAVERSE(&queries, query, list) { 01234 if (!strcmp(query->acf->name, a->argv[2])) { 01235 break; 01236 } 01237 } 01238 01239 if (!query) { 01240 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]); 01241 AST_RWLIST_UNLOCK(&queries); 01242 return CLI_SHOWUSAGE; 01243 } 01244 01245 if (ast_strlen_zero(query->sql_write)) { 01246 ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]); 01247 AST_RWLIST_UNLOCK(&queries); 01248 return CLI_SUCCESS; 01249 } 01250 01251 ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300); 01252 01253 /* Evaluate function */ 01254 char_args = ast_strdupa(a->argv[3]); 01255 char_values = ast_strdupa(a->argv[4]); 01256 01257 chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"); 01258 01259 AST_STANDARD_APP_ARGS(args, char_args); 01260 for (i = 0; i < args.argc; i++) { 01261 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 01262 pbx_builtin_pushvar_helper(chan, varname, args.field[i]); 01263 } 01264 01265 /* Parse values, just like arguments */ 01266 AST_STANDARD_APP_ARGS(values, char_values); 01267 for (i = 0; i < values.argc; i++) { 01268 snprintf(varname, sizeof(varname), "VAL%d", i + 1); 01269 pbx_builtin_pushvar_helper(chan, varname, values.field[i]); 01270 } 01271 01272 /* Additionally set the value as a whole (but push an empty string if value is NULL) */ 01273 pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], "")); 01274 ast_str_substitute_variables(&sql, 0, chan, query->sql_write); 01275 ast_debug(1, "SQL is %s\n", ast_str_buffer(sql)); 01276 ast_channel_free(chan); 01277 01278 if (a->argc == 6 && !strcmp(a->argv[5], "exec")) { 01279 /* Execute the query */ 01280 struct odbc_obj *obj = NULL; 01281 int dsn, executed = 0; 01282 SQLHSTMT stmt; 01283 SQLLEN rows = -1; 01284 01285 for (dsn = 0; dsn < 5; dsn++) { 01286 if (ast_strlen_zero(query->writehandle[dsn])) { 01287 continue; 01288 } 01289 if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) { 01290 continue; 01291 } 01292 if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { 01293 ast_odbc_release_obj(obj); 01294 obj = NULL; 01295 continue; 01296 } 01297 01298 SQLRowCount(stmt, &rows); 01299 SQLCloseCursor(stmt); 01300 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 01301 ast_odbc_release_obj(obj); 01302 obj = NULL; 01303 ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn, query->writehandle[dsn]); 01304 executed = 1; 01305 break; 01306 } 01307 01308 if (!executed) { 01309 ast_cli(a->fd, "Failed to execute query.\n"); 01310 } 01311 } else { /* No execution, just print out the resulting SQL */ 01312 ast_cli(a->fd, "%s\n", ast_str_buffer(sql)); 01313 } 01314 AST_RWLIST_UNLOCK(&queries); 01315 return CLI_SUCCESS; 01316 }
| static int exec_odbcfinish | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 735 of file func_odbc.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_datastore_free(), and odbc_info.
Referenced by load_module().
00736 { 00737 struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data); 00738 if (!store) /* Already freed; no big deal. */ 00739 return 0; 00740 ast_channel_datastore_remove(chan, store); 00741 ast_datastore_free(store); 00742 return 0; 00743 }
| static int free_acf_query | ( | struct acf_odbc_query * | query | ) | [static] |
Definition at line 964 of file func_odbc.c.
References acf_odbc_query::acf, ast_free, ast_string_field_free_memory, and ast_custom_function::name.
Referenced by reload(), and unload_module().
| static SQLHSTMT generic_execute | ( | struct odbc_obj * | obj, | |
| void * | data | |||
| ) | [static] |
Definition at line 160 of file func_odbc.c.
References ast_log(), odbc_obj::con, and LOG_WARNING.
Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), and cli_odbc_write().
00161 { 00162 int res; 00163 char *sql = data; 00164 SQLHSTMT stmt; 00165 00166 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); 00167 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00168 ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res); 00169 return NULL; 00170 } 00171 00172 res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS); 00173 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00174 if (res == SQL_ERROR) { 00175 int i; 00176 SQLINTEGER nativeerror=0, numfields=0; 00177 SQLSMALLINT diagbytes=0; 00178 unsigned char state[10], diagnostic[256]; 00179 00180 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00181 for (i = 0; i < numfields; i++) { 00182 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00183 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00184 if (i > 10) { 00185 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00186 break; 00187 } 00188 } 00189 } 00190 00191 ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql); 00192 SQLCloseCursor(stmt); 00193 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00194 return NULL; 00195 } 00196 00197 return stmt; 00198 }
| static int init_acf_query | ( | struct ast_config * | cfg, | |
| char * | catg, | |||
| struct acf_odbc_query ** | query | |||
| ) | [static] |
Definition at line 745 of file func_odbc.c.
References acf_odbc_query::acf, acf_odbc_read(), acf_odbc_write(), asprintf, AST_APP_ARG, ast_calloc, ast_clear_flag, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_false(), ast_free, ast_log(), ast_set_flag, AST_STANDARD_APP_ARGS, ast_string_field_build, ast_string_field_free_memory, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_retrieve(), desc, dsn, errno, LOG_ERROR, LOG_WARNING, OPT_ESCAPECOMMAS, OPT_MULTIROW, ast_custom_function::read, and synopsis.
Referenced by load_module(), and reload().
00746 { 00747 const char *tmp; 00748 int i; 00749 00750 if (!cfg || !catg) { 00751 return EINVAL; 00752 } 00753 00754 *query = ast_calloc(1, sizeof(struct acf_odbc_query)); 00755 if (! (*query)) 00756 return ENOMEM; 00757 00758 if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) { 00759 char *tmp2 = ast_strdupa(tmp); 00760 AST_DECLARE_APP_ARGS(writeconf, 00761 AST_APP_ARG(dsn)[5]; 00762 ); 00763 AST_STANDARD_APP_ARGS(writeconf, tmp2); 00764 for (i = 0; i < 5; i++) { 00765 if (!ast_strlen_zero(writeconf.dsn[i])) 00766 ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i])); 00767 } 00768 } 00769 00770 if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) { 00771 char *tmp2 = ast_strdupa(tmp); 00772 AST_DECLARE_APP_ARGS(readconf, 00773 AST_APP_ARG(dsn)[5]; 00774 ); 00775 AST_STANDARD_APP_ARGS(readconf, tmp2); 00776 for (i = 0; i < 5; i++) { 00777 if (!ast_strlen_zero(readconf.dsn[i])) 00778 ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i])); 00779 } 00780 } else { 00781 /* If no separate readhandle, then use the writehandle for reading */ 00782 for (i = 0; i < 5; i++) { 00783 if (!ast_strlen_zero((*query)->writehandle[i])) 00784 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i])); 00785 } 00786 } 00787 00788 if ((tmp = ast_variable_retrieve(cfg, catg, "readsql"))) 00789 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00790 else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { 00791 ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); 00792 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00793 } 00794 00795 if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) { 00796 ast_free(*query); 00797 *query = NULL; 00798 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg); 00799 return EINVAL; 00800 } 00801 00802 if ((tmp = ast_variable_retrieve(cfg, catg, "writesql"))) 00803 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00804 else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { 00805 ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); 00806 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00807 } 00808 00809 if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) { 00810 ast_free(*query); 00811 *query = NULL; 00812 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg); 00813 return EINVAL; 00814 } 00815 00816 if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) { 00817 ast_copy_string((*query)->sql_insert, tmp, sizeof((*query)->sql_insert)); 00818 } 00819 00820 /* Allow escaping of embedded commas in fields to be turned off */ 00821 ast_set_flag((*query), OPT_ESCAPECOMMAS); 00822 if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) { 00823 if (ast_false(tmp)) 00824 ast_clear_flag((*query), OPT_ESCAPECOMMAS); 00825 } 00826 00827 if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) { 00828 if (strcasecmp(tmp, "multirow") == 0) 00829 ast_set_flag((*query), OPT_MULTIROW); 00830 if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit"))) 00831 sscanf(tmp, "%30d", &((*query)->rowlimit)); 00832 } 00833 00834 (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function)); 00835 if (! (*query)->acf) { 00836 ast_free(*query); 00837 *query = NULL; 00838 return ENOMEM; 00839 } 00840 if (ast_string_field_init((*query)->acf, 128)) { 00841 ast_free((*query)->acf); 00842 ast_free(*query); 00843 *query = NULL; 00844 return ENOMEM; 00845 } 00846 00847 if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { 00848 if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) { 00849 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00850 } 00851 } else { 00852 if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) { 00853 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00854 } 00855 } 00856 00857 if (!((*query)->acf->name)) { 00858 ast_string_field_free_memory((*query)->acf); 00859 ast_free((*query)->acf); 00860 ast_free(*query); 00861 *query = NULL; 00862 return ENOMEM; 00863 } 00864 00865 if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) { 00866 ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp); 00867 } else { 00868 ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name); 00869 } 00870 00871 if (ast_strlen_zero((*query)->acf->syntax)) { 00872 ast_free((char *)(*query)->acf->name); 00873 ast_string_field_free_memory((*query)->acf); 00874 ast_free((*query)->acf); 00875 ast_free(*query); 00876 *query = NULL; 00877 return ENOMEM; 00878 } 00879 00880 if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) { 00881 ast_string_field_set((*query)->acf, synopsis, tmp); 00882 } else { 00883 ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments"); 00884 } 00885 00886 if (ast_strlen_zero((*query)->acf->synopsis)) { 00887 ast_free((char *)(*query)->acf->name); 00888 ast_string_field_free_memory((*query)->acf); 00889 ast_free((*query)->acf); 00890 ast_free(*query); 00891 *query = NULL; 00892 return ENOMEM; 00893 } 00894 00895 if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { 00896 ast_string_field_build((*query)->acf, desc, 00897 "Runs the following query, as defined in func_odbc.conf, performing\n" 00898 "substitution of the arguments into the query as specified by ${ARG1},\n" 00899 "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" 00900 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00901 "%s" 00902 "\nRead:\n%s\n\nWrite:\n%s\n%s%s%s", 00903 ast_strlen_zero((*query)->sql_insert) ? "" : 00904 "If the write query affects no rows, the insert query will be\n" 00905 "performed.\n", 00906 (*query)->sql_read, 00907 (*query)->sql_write, 00908 ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n", 00909 ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, 00910 ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); 00911 } else if (!ast_strlen_zero((*query)->sql_read)) { 00912 ast_string_field_build((*query)->acf, desc, 00913 "Runs the following query, as defined in func_odbc.conf, performing\n" 00914 "substitution of the arguments into the query as specified by ${ARG1},\n" 00915 "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", 00916 (*query)->sql_read); 00917 } else if (!ast_strlen_zero((*query)->sql_write)) { 00918 ast_string_field_build((*query)->acf, desc, 00919 "Runs the following query, as defined in func_odbc.conf, performing\n" 00920 "substitution of the arguments into the query as specified by ${ARG1},\n" 00921 "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" 00922 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00923 "This function may only be set.\n%sSQL:\n%s\n%s%s%s", 00924 ast_strlen_zero((*query)->sql_insert) ? "" : 00925 "If the write query affects no rows, the insert query will be\n" 00926 "performed.\n", 00927 (*query)->sql_write, 00928 ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n", 00929 ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, 00930 ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); 00931 } else { 00932 ast_string_field_free_memory((*query)->acf); 00933 ast_free((char *)(*query)->acf->name); 00934 ast_free((*query)->acf); 00935 ast_free(*query); 00936 ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg); 00937 return EINVAL; 00938 } 00939 00940 if (ast_strlen_zero((*query)->acf->desc)) { 00941 ast_string_field_free_memory((*query)->acf); 00942 ast_free((char *)(*query)->acf->name); 00943 ast_free((*query)->acf); 00944 ast_free(*query); 00945 *query = NULL; 00946 return ENOMEM; 00947 } 00948 00949 if (ast_strlen_zero((*query)->sql_read)) { 00950 (*query)->acf->read = NULL; 00951 } else { 00952 (*query)->acf->read = acf_odbc_read; 00953 } 00954 00955 if (ast_strlen_zero((*query)->sql_write)) { 00956 (*query)->acf->write = NULL; 00957 } else { 00958 (*query)->acf->write = acf_odbc_write; 00959 } 00960 00961 return 0; 00962 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1323 of file func_odbc.c.
References acf_odbc_query::acf, app_odbcfinish, ARRAY_LEN, ast_category_browse(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application_xml, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, cli_func_odbc, CONFIG_STATUS_FILEINVALID, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), acf_odbc_query::list, LOG_ERROR, and LOG_NOTICE.
01324 { 01325 int res = 0; 01326 struct ast_config *cfg; 01327 char *catg; 01328 struct ast_flags config_flags = { 0 }; 01329 01330 res |= ast_custom_function_register(&fetch_function); 01331 res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish); 01332 AST_RWLIST_WRLOCK(&queries); 01333 01334 cfg = ast_config_load(config, config_flags); 01335 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { 01336 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); 01337 AST_RWLIST_UNLOCK(&queries); 01338 return AST_MODULE_LOAD_DECLINE; 01339 } 01340 01341 for (catg = ast_category_browse(cfg, NULL); 01342 catg; 01343 catg = ast_category_browse(cfg, catg)) { 01344 struct acf_odbc_query *query = NULL; 01345 int err; 01346 01347 if ((err = init_acf_query(cfg, catg, &query))) { 01348 if (err == ENOMEM) 01349 ast_log(LOG_ERROR, "Out of memory\n"); 01350 else if (err == EINVAL) 01351 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg); 01352 else 01353 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err); 01354 } else { 01355 AST_RWLIST_INSERT_HEAD(&queries, query, list); 01356 ast_custom_function_register(query->acf); 01357 } 01358 } 01359 01360 ast_config_destroy(cfg); 01361 res |= ast_custom_function_register(&escape_function); 01362 ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc)); 01363 01364 AST_RWLIST_UNLOCK(&queries); 01365 return res; 01366 }
| static void odbc_datastore_free | ( | void * | data | ) | [static] |
Definition at line 147 of file func_odbc.c.
References ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and acf_odbc_query::list.
Referenced by acf_odbc_read().
00148 { 00149 struct odbc_datastore *result = data; 00150 struct odbc_datastore_row *row; 00151 AST_LIST_LOCK(result); 00152 while ((row = AST_LIST_REMOVE_HEAD(result, list))) { 00153 ast_free(row); 00154 } 00155 AST_LIST_UNLOCK(result); 00156 AST_LIST_HEAD_DESTROY(result); 00157 ast_free(result); 00158 }
| static int reload | ( | void | ) | [static] |
Definition at line 1394 of file func_odbc.c.
References acf_odbc_query::acf, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_custom_function_unregister(), ast_log(), AST_RWLIST_EMPTY, AST_RWLIST_INSERT_HEAD, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, free_acf_query(), init_acf_query(), acf_odbc_query::list, LOG_ERROR, and LOG_WARNING.
01395 { 01396 int res = 0; 01397 struct ast_config *cfg; 01398 struct acf_odbc_query *oldquery; 01399 char *catg; 01400 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; 01401 01402 cfg = ast_config_load(config, config_flags); 01403 if (cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) 01404 return 0; 01405 01406 AST_RWLIST_WRLOCK(&queries); 01407 01408 while (!AST_RWLIST_EMPTY(&queries)) { 01409 oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list); 01410 ast_custom_function_unregister(oldquery->acf); 01411 free_acf_query(oldquery); 01412 } 01413 01414 if (!cfg) { 01415 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); 01416 goto reload_out; 01417 } 01418 01419 for (catg = ast_category_browse(cfg, NULL); 01420 catg; 01421 catg = ast_category_browse(cfg, catg)) { 01422 struct acf_odbc_query *query = NULL; 01423 01424 if (init_acf_query(cfg, catg, &query)) { 01425 ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); 01426 } else { 01427 AST_RWLIST_INSERT_HEAD(&queries, query, list); 01428 ast_custom_function_register(query->acf); 01429 } 01430 } 01431 01432 ast_config_destroy(cfg); 01433 reload_out: 01434 AST_RWLIST_UNLOCK(&queries); 01435 return res; 01436 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1368 of file func_odbc.c.
References acf_odbc_query::acf, app_odbcfinish, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), AST_RWLIST_EMPTY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_unregister_application(), cli_func_odbc, escape_function, fetch_function, free_acf_query(), and acf_odbc_query::list.
01369 { 01370 struct acf_odbc_query *query; 01371 int res = 0; 01372 01373 AST_RWLIST_WRLOCK(&queries); 01374 while (!AST_RWLIST_EMPTY(&queries)) { 01375 query = AST_RWLIST_REMOVE_HEAD(&queries, list); 01376 ast_custom_function_unregister(query->acf); 01377 free_acf_query(query); 01378 } 01379 01380 res |= ast_custom_function_unregister(&escape_function); 01381 res |= ast_custom_function_unregister(&fetch_function); 01382 res |= ast_unregister_application(app_odbcfinish); 01383 ast_cli_unregister_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc)); 01384 01385 /* Allow any threads waiting for this lock to pass (avoids a race) */ 01386 AST_RWLIST_UNLOCK(&queries); 01387 usleep(1); 01388 AST_RWLIST_WRLOCK(&queries); 01389 01390 AST_RWLIST_UNLOCK(&queries); 01391 return 0; 01392 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ODBC lookups" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1444 of file func_odbc.c.
char* app_odbcfinish = "ODBCFinish" [static] |
Definition at line 733 of file func_odbc.c.
Referenced by load_module(), and unload_module().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1444 of file func_odbc.c.
struct ast_cli_entry cli_func_odbc[] [static] |
{
AST_CLI_DEFINE(cli_odbc_write, "Test setting a func_odbc function"),
AST_CLI_DEFINE(cli_odbc_read, "Test reading a func_odbc function"),
}
Definition at line 1318 of file func_odbc.c.
Referenced by load_module(), and unload_module().
struct ast_threadstorage coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , } [static] |
Definition at line 144 of file func_odbc.c.
Referenced by acf_odbc_read(), and cli_odbc_read().
struct ast_threadstorage colnames_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_colnames_buf , .custom_init = NULL , } [static] |
Definition at line 145 of file func_odbc.c.
Referenced by acf_odbc_read().
char* config = "func_odbc.conf" [static] |
Definition at line 100 of file func_odbc.c.
struct ast_custom_function escape_function [static] |
{
.name = "SQL_ESC",
.read = acf_escape,
.write = NULL,
}
Definition at line 693 of file func_odbc.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function fetch_function [static] |
{
.name = "ODBC_FETCH",
.read = acf_fetch,
.write = NULL,
}
Definition at line 727 of file func_odbc.c.
Referenced by load_module(), and unload_module().
| struct ast_datastore_info odbc_info |
{
.type = "FUNC_ODBC",
.destroy = odbc_datastore_free,
}
Definition at line 121 of file func_odbc.c.
Referenced by acf_fetch(), acf_odbc_read(), and exec_odbcfinish().
| enum { ... } odbc_option_flags |
int resultcount = 0 [static] |
Definition at line 140 of file func_odbc.c.
Referenced by acf_odbc_read().
struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , } [static] |
Definition at line 143 of file func_odbc.c.
Referenced by acf_odbc_write().
struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , } [static] |
Definition at line 142 of file func_odbc.c.
Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), and cli_odbc_write().
1.6.2