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