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