#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"
Go to the source code of this file.
Data Structures | |
struct | acf_odbc_query |
struct | odbc_datastore |
struct | odbc_datastore_row |
struct | queries |
Enumerations | |
enum | { OPT_ESCAPECOMMAS = (1 << 0), OPT_MULTIROW = (1 << 1) } |
Functions | |
static void | __init_coldata_buf (void) |
static void | __init_colnames_buf (void) |
static void | __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 int | exec_odbcfinish (struct ast_channel *chan, void *data) |
static int | free_acf_query (struct acf_odbc_query *query) |
static SQLHSTMT | generic_execute (struct odbc_obj *obj, void *data) |
static int | init_acf_query (struct ast_config *cfg, char *catg, struct acf_odbc_query **query) |
static int | load_module (void) |
static void | odbc_datastore_free (void *data) |
static int | reload (void) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ODBC lookups" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .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_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 char * | desc_odbcfinish |
static struct ast_custom_function | escape_function |
static struct ast_custom_function | fetch_function |
ast_datastore_info | odbc_info |
enum { ... } | odbc_option_flags |
static int | resultcount = 0 |
static char * | syn_odbcfinish = "Clear the resultset of a successful multirow query" |
Definition in file func_odbc.c.
anonymous enum |
Definition at line 49 of file func_odbc.c.
00049 { 00050 OPT_ESCAPECOMMAS = (1 << 0), 00051 OPT_MULTIROW = (1 << 1), 00052 } odbc_option_flags;
static void __init_coldata_buf | ( | void | ) | [static] |
static void __init_colnames_buf | ( | void | ) | [static] |
static void __reg_module | ( | void | ) | [static] |
Definition at line 960 of file func_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 960 of file func_odbc.c.
static int acf_escape | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 554 of file func_odbc.c.
00555 { 00556 char *out = buf; 00557 00558 for (; *data && out - buf < len; data++) { 00559 if (*data == '\'') { 00560 *out = '\''; 00561 out++; 00562 } 00563 *out++ = *data; 00564 } 00565 *out = '\0'; 00566 00567 return 0; 00568 }
static int acf_fetch | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 582 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, chan, odbc_datastore_row::data, ast_datastore::data, odbc_datastore_row::list, odbc_datastore::names, odbc_info, and pbx_builtin_setvar_helper().
00583 { 00584 struct ast_datastore *store; 00585 struct odbc_datastore *resultset; 00586 struct odbc_datastore_row *row; 00587 store = ast_channel_datastore_find(chan, &odbc_info, data); 00588 if (!store) { 00589 return -1; 00590 } 00591 resultset = store->data; 00592 AST_LIST_LOCK(resultset); 00593 row = AST_LIST_REMOVE_HEAD(resultset, list); 00594 AST_LIST_UNLOCK(resultset); 00595 if (!row) { 00596 /* Cleanup datastore */ 00597 ast_channel_datastore_remove(chan, store); 00598 ast_datastore_free(store); 00599 return -1; 00600 } 00601 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names); 00602 ast_copy_string(buf, row->data, len); 00603 ast_free(row); 00604 return 0; 00605 }
static int acf_odbc_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | s, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 260 of file func_odbc.c.
References acf_odbc_query::acf, AST_APP_ARG, ast_autoservice_start(), ast_calloc, ast_channel_alloc, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD_INIT, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer, ast_str_create(), ast_str_make_space(), ast_str_reset(), ast_str_size, ast_str_strlen, ast_str_thread_get(), ast_str_update, ast_strlen_zero(), ast_test_flag, chan, colnames_buf, dsn, generic_execute(), acf_odbc_query::list, LOG_ERROR, ast_custom_function::name, OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), acf_odbc_query::readhandle, acf_odbc_query::rowlimit, acf_odbc_query::sql_read, and ast_str::str.
Referenced by init_acf_query().
00261 { 00262 struct odbc_obj *obj = NULL; 00263 struct acf_odbc_query *query; 00264 char varname[15], rowcount[12] = "-1"; 00265 struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16); 00266 int res, x, y, buflen = 0, escapecommas, rowlimit = 1, dsn, bogus_chan = 0; 00267 AST_DECLARE_APP_ARGS(args, 00268 AST_APP_ARG(field)[100]; 00269 ); 00270 SQLHSTMT stmt = NULL; 00271 SQLSMALLINT colcount=0; 00272 SQLLEN indicator; 00273 SQLSMALLINT collength; 00274 struct odbc_datastore *resultset = NULL; 00275 struct odbc_datastore_row *row = NULL; 00276 struct ast_str *sql = ast_str_create(16); 00277 00278 if (!sql) { 00279 return -1; 00280 } 00281 00282 ast_str_reset(colnames); 00283 00284 AST_RWLIST_RDLOCK(&queries); 00285 AST_RWLIST_TRAVERSE(&queries, query, list) { 00286 if (!strcmp(query->acf->name, cmd)) { 00287 break; 00288 } 00289 } 00290 00291 if (!query) { 00292 ast_log(LOG_ERROR, "No such function '%s'\n", cmd); 00293 AST_RWLIST_UNLOCK(&queries); 00294 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00295 ast_free(sql); 00296 return -1; 00297 } 00298 00299 if (!chan) { 00300 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) 00301 bogus_chan = 1; 00302 } 00303 00304 if (chan) 00305 ast_autoservice_start(chan); 00306 00307 AST_STANDARD_APP_ARGS(args, s); 00308 for (x = 0; x < args.argc; x++) { 00309 snprintf(varname, sizeof(varname), "ARG%d", x + 1); 00310 pbx_builtin_pushvar_helper(chan, varname, args.field[x]); 00311 } 00312 00313 do { 00314 ast_str_make_space(&sql, 2 * (strlen(query->sql_read) > ast_str_size(sql) ? strlen(query->sql_read) : ast_str_size(sql))); 00315 pbx_substitute_variables_helper(chan, query->sql_read, ast_str_buffer(sql), ast_str_size(sql) - 1); 00316 ast_str_update(sql); 00317 } while (ast_str_strlen(sql) > ast_str_size(sql) - 5); 00318 00319 /* Restore prior values */ 00320 for (x = 0; x < args.argc; x++) { 00321 snprintf(varname, sizeof(varname), "ARG%d", x + 1); 00322 pbx_builtin_setvar_helper(chan, varname, NULL); 00323 } 00324 00325 /* Save these flags, so we can release the lock */ 00326 escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS); 00327 if (ast_test_flag(query, OPT_MULTIROW)) { 00328 resultset = ast_calloc(1, sizeof(*resultset)); 00329 AST_LIST_HEAD_INIT(resultset); 00330 if (query->rowlimit) 00331 rowlimit = query->rowlimit; 00332 else 00333 rowlimit = INT_MAX; 00334 } 00335 AST_RWLIST_UNLOCK(&queries); 00336 00337 for (dsn = 0; dsn < 5; dsn++) { 00338 if (!ast_strlen_zero(query->readhandle[dsn])) { 00339 obj = ast_odbc_request_obj(query->readhandle[dsn], 0); 00340 if (obj) 00341 stmt = ast_odbc_direct_execute(obj, generic_execute, sql->str); 00342 } 00343 if (stmt) 00344 break; 00345 } 00346 00347 if (!stmt) { 00348 ast_log(LOG_ERROR, "Unable to execute query [%s]\n", sql->str); 00349 if (obj) 00350 ast_odbc_release_obj(obj); 00351 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00352 if (chan) 00353 ast_autoservice_stop(chan); 00354 if (bogus_chan) 00355 ast_channel_free(chan); 00356 ast_free(sql); 00357 return -1; 00358 } 00359 00360 res = SQLNumResultCols(stmt, &colcount); 00361 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00362 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql->str); 00363 SQLCloseCursor(stmt); 00364 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00365 ast_odbc_release_obj(obj); 00366 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00367 if (chan) 00368 ast_autoservice_stop(chan); 00369 if (bogus_chan) 00370 ast_channel_free(chan); 00371 ast_free(sql); 00372 return -1; 00373 } 00374 00375 res = SQLFetch(stmt); 00376 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00377 int res1 = -1; 00378 if (res == SQL_NO_DATA) { 00379 ast_verb(4, "Found no rows [%s]\n", sql->str); 00380 res1 = 0; 00381 buf[0] = '\0'; 00382 ast_copy_string(rowcount, "0", sizeof(rowcount)); 00383 } else { 00384 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str); 00385 } 00386 SQLCloseCursor(stmt); 00387 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00388 ast_odbc_release_obj(obj); 00389 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00390 if (chan) 00391 ast_autoservice_stop(chan); 00392 if (bogus_chan) 00393 ast_channel_free(chan); 00394 ast_free(sql); 00395 return res1; 00396 } 00397 00398 for (y = 0; y < rowlimit; y++) { 00399 buf[0] = '\0'; 00400 for (x = 0; x < colcount; x++) { 00401 int i; 00402 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16); 00403 00404 if (y == 0) { 00405 char colname[256]; 00406 SQLULEN maxcol; 00407 00408 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL); 00409 ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x); 00410 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { 00411 snprintf(colname, sizeof(colname), "field%d", x); 00412 } 00413 00414 if (coldata->len < maxcol + 1) { 00415 ast_str_make_space(&coldata, maxcol + 1); 00416 } 00417 00418 if (colnames->used) { 00419 ast_str_append(&colnames, 0, ","); 00420 } 00421 ast_str_make_space(&colnames, strlen(colname) * 2 + 1 + colnames->used); 00422 00423 /* Copy data, encoding '\' and ',' for the argument parser */ 00424 for (i = 0; i < sizeof(colname); i++) { 00425 if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) { 00426 colnames->str[colnames->used++] = '\\'; 00427 } 00428 colnames->str[colnames->used++] = colname[i]; 00429 00430 if (colname[i] == '\0') { 00431 colnames->used--; 00432 break; 00433 } 00434 } 00435 00436 if (resultset) { 00437 void *tmp = ast_realloc(resultset, sizeof(*resultset) + colnames->used + 1); 00438 if (!tmp) { 00439 ast_log(LOG_ERROR, "No space for a new resultset?\n"); 00440 ast_free(resultset); 00441 SQLCloseCursor(stmt); 00442 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00443 ast_odbc_release_obj(obj); 00444 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00445 if (chan) 00446 ast_autoservice_stop(chan); 00447 if (bogus_chan) 00448 ast_channel_free(chan); 00449 ast_free(sql); 00450 return -1; 00451 } 00452 resultset = tmp; 00453 strcpy((char *)resultset + sizeof(*resultset), colnames->str); 00454 } 00455 } 00456 00457 buflen = strlen(buf); 00458 res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata->str, coldata->len, &indicator); 00459 if (indicator == SQL_NULL_DATA) { 00460 ast_debug(3, "Got NULL data\n"); 00461 ast_str_reset(coldata); 00462 res = SQL_SUCCESS; 00463 } 00464 00465 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00466 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql->str); 00467 y = -1; 00468 buf[0] = '\0'; 00469 goto end_acf_read; 00470 } 00471 00472 ast_debug(2, "Got coldata of '%s'\n", coldata->str); 00473 coldata->used = strlen(coldata->str); 00474 00475 /* Copy data, encoding '\' and ',' for the argument parser */ 00476 for (i = 0; i < coldata->used; i++) { 00477 if (escapecommas && (coldata->str[i] == '\\' || coldata->str[i] == ',')) { 00478 buf[buflen++] = '\\'; 00479 } 00480 buf[buflen++] = coldata->str[i]; 00481 00482 if (buflen >= len - 2) 00483 break; 00484 00485 if (coldata->str[i] == '\0') 00486 break; 00487 } 00488 00489 buf[buflen++] = ','; 00490 buf[buflen] = '\0'; 00491 ast_debug(2, "buf is now set to '%s'\n", buf); 00492 } 00493 /* Trim trailing comma */ 00494 buf[buflen - 1] = '\0'; 00495 ast_debug(2, "buf is now set to '%s'\n", buf); 00496 00497 if (resultset) { 00498 row = ast_calloc(1, sizeof(*row) + buflen); 00499 if (!row) { 00500 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n"); 00501 goto end_acf_read; 00502 } 00503 strcpy((char *)row + sizeof(*row), buf); 00504 AST_LIST_INSERT_TAIL(resultset, row, list); 00505 00506 /* Get next row */ 00507 res = SQLFetch(stmt); 00508 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00509 if (res != SQL_NO_DATA) 00510 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str); 00511 y++; 00512 break; 00513 } 00514 } 00515 } 00516 00517 end_acf_read: 00518 snprintf(rowcount, sizeof(rowcount), "%d", y); 00519 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00520 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames->str); 00521 if (resultset) { 00522 int uid; 00523 struct ast_datastore *odbc_store; 00524 uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1; 00525 snprintf(buf, len, "%d", uid); 00526 odbc_store = ast_datastore_alloc(&odbc_info, buf); 00527 if (!odbc_store) { 00528 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n"); 00529 odbc_datastore_free(resultset); 00530 SQLCloseCursor(stmt); 00531 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00532 ast_odbc_release_obj(obj); 00533 if (chan) 00534 ast_autoservice_stop(chan); 00535 if (bogus_chan) 00536 ast_channel_free(chan); 00537 ast_free(sql); 00538 return -1; 00539 } 00540 odbc_store->data = resultset; 00541 ast_channel_datastore_add(chan, odbc_store); 00542 } 00543 SQLCloseCursor(stmt); 00544 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00545 ast_odbc_release_obj(obj); 00546 if (chan) 00547 ast_autoservice_stop(chan); 00548 if (bogus_chan) 00549 ast_channel_free(chan); 00550 ast_free(sql); 00551 return 0; 00552 }
static int acf_odbc_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | s, | |||
const char * | value | |||
) | [static] |
Definition at line 130 of file func_odbc.c.
References acf_odbc_query::acf, AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_alloc, ast_channel_free(), AST_DECLARE_APP_ARGS, ast_free, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer, ast_str_create(), ast_str_make_space(), ast_str_size, ast_str_strlen, ast_str_update, ast_strdupa, ast_strlen_zero(), buf, chan, dsn, generic_execute(), acf_odbc_query::list, LOG_ERROR, ast_custom_function::name, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), acf_odbc_query::sql_write, and acf_odbc_query::writehandle.
Referenced by init_acf_query().
00131 { 00132 struct odbc_obj *obj = NULL; 00133 struct acf_odbc_query *query; 00134 char *t, varname[15]; 00135 int i, dsn, bogus_chan = 0; 00136 AST_DECLARE_APP_ARGS(values, 00137 AST_APP_ARG(field)[100]; 00138 ); 00139 AST_DECLARE_APP_ARGS(args, 00140 AST_APP_ARG(field)[100]; 00141 ); 00142 SQLHSTMT stmt = NULL; 00143 SQLLEN rows=0; 00144 struct ast_str *buf = ast_str_create(16); 00145 00146 if (!buf) { 00147 return -1; 00148 } 00149 00150 AST_RWLIST_RDLOCK(&queries); 00151 AST_RWLIST_TRAVERSE(&queries, query, list) { 00152 if (!strcmp(query->acf->name, cmd)) { 00153 break; 00154 } 00155 } 00156 00157 if (!query) { 00158 ast_log(LOG_ERROR, "No such function '%s'\n", cmd); 00159 AST_RWLIST_UNLOCK(&queries); 00160 ast_free(buf); 00161 return -1; 00162 } 00163 00164 if (!chan) { 00165 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) 00166 bogus_chan = 1; 00167 } 00168 00169 if (chan) 00170 ast_autoservice_start(chan); 00171 00172 /* Parse our arguments */ 00173 t = value ? ast_strdupa(value) : ""; 00174 00175 if (!s || !t) { 00176 ast_log(LOG_ERROR, "Out of memory\n"); 00177 AST_RWLIST_UNLOCK(&queries); 00178 if (chan) 00179 ast_autoservice_stop(chan); 00180 if (bogus_chan) 00181 ast_channel_free(chan); 00182 ast_free(buf); 00183 return -1; 00184 } 00185 00186 AST_STANDARD_APP_ARGS(args, s); 00187 for (i = 0; i < args.argc; i++) { 00188 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 00189 pbx_builtin_pushvar_helper(chan, varname, args.field[i]); 00190 } 00191 00192 /* Parse values, just like arguments */ 00193 AST_STANDARD_APP_ARGS(values, t); 00194 for (i = 0; i < values.argc; i++) { 00195 snprintf(varname, sizeof(varname), "VAL%d", i + 1); 00196 pbx_builtin_pushvar_helper(chan, varname, values.field[i]); 00197 } 00198 00199 /* Additionally set the value as a whole (but push an empty string if value is NULL) */ 00200 pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : ""); 00201 00202 do { 00203 ast_str_make_space(&buf, 2 * (strlen(query->sql_write) > ast_str_size(buf) ? strlen(query->sql_write) : ast_str_size(buf))); 00204 pbx_substitute_variables_helper(chan, query->sql_write, ast_str_buffer(buf), ast_str_size(buf) - 1); 00205 ast_str_update(buf); 00206 } while (ast_str_strlen(buf) > ast_str_size(buf) - 5); 00207 00208 /* Restore prior values */ 00209 for (i = 0; i < args.argc; i++) { 00210 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 00211 pbx_builtin_setvar_helper(chan, varname, NULL); 00212 } 00213 00214 for (i = 0; i < values.argc; i++) { 00215 snprintf(varname, sizeof(varname), "VAL%d", i + 1); 00216 pbx_builtin_setvar_helper(chan, varname, NULL); 00217 } 00218 pbx_builtin_setvar_helper(chan, "VALUE", NULL); 00219 00220 AST_RWLIST_UNLOCK(&queries); 00221 00222 for (dsn = 0; dsn < 5; dsn++) { 00223 if (!ast_strlen_zero(query->writehandle[dsn])) { 00224 obj = ast_odbc_request_obj(query->writehandle[dsn], 0); 00225 if (obj) 00226 stmt = ast_odbc_direct_execute(obj, generic_execute, buf->str); 00227 } 00228 if (stmt) 00229 break; 00230 } 00231 00232 if (stmt) { 00233 /* Rows affected */ 00234 SQLRowCount(stmt, &rows); 00235 } 00236 00237 /* Output the affected rows, for all cases. In the event of failure, we 00238 * flag this as -1 rows. Note that this is different from 0 affected rows 00239 * which would be the case if we succeeded in our query, but the values did 00240 * not change. */ 00241 snprintf(varname, sizeof(varname), "%d", (int)rows); 00242 pbx_builtin_setvar_helper(chan, "ODBCROWS", varname); 00243 00244 if (stmt) { 00245 SQLCloseCursor(stmt); 00246 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00247 } 00248 if (obj) 00249 ast_odbc_release_obj(obj); 00250 00251 if (chan) 00252 ast_autoservice_stop(chan); 00253 if (bogus_chan) 00254 ast_channel_free(chan); 00255 ast_free(buf); 00256 00257 return 0; 00258 }
static int exec_odbcfinish | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 626 of file func_odbc.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_datastore_free(), chan, and odbc_info.
Referenced by load_module().
00627 { 00628 struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data); 00629 if (!store) /* Already freed; no big deal. */ 00630 return 0; 00631 ast_channel_datastore_remove(chan, store); 00632 ast_datastore_free(store); 00633 return 0; 00634 }
static int free_acf_query | ( | struct acf_odbc_query * | query | ) | [static] |
Definition at line 824 of file func_odbc.c.
References acf_odbc_query::acf, ast_free, ast_custom_function::desc, ast_custom_function::name, and ast_custom_function::syntax.
Referenced by reload(), and unload_module().
00825 { 00826 if (query) { 00827 if (query->acf) { 00828 if (query->acf->name) 00829 ast_free((char *)query->acf->name); 00830 if (query->acf->syntax) 00831 ast_free((char *)query->acf->syntax); 00832 if (query->acf->desc) 00833 ast_free((char *)query->acf->desc); 00834 ast_free(query->acf); 00835 } 00836 ast_free(query); 00837 } 00838 return 0; 00839 }
static SQLHSTMT generic_execute | ( | struct odbc_obj * | obj, | |
void * | data | |||
) | [static] |
Definition at line 104 of file func_odbc.c.
References ast_log(), odbc_obj::con, and LOG_WARNING.
Referenced by acf_odbc_read(), and acf_odbc_write().
00105 { 00106 int res; 00107 char *sql = data; 00108 SQLHSTMT stmt; 00109 00110 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); 00111 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00112 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00113 return NULL; 00114 } 00115 00116 res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS); 00117 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00118 ast_log(LOG_WARNING, "SQL Exec Direct failed![%s]\n", sql); 00119 SQLCloseCursor(stmt); 00120 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00121 return NULL; 00122 } 00123 00124 return stmt; 00125 }
static int init_acf_query | ( | struct ast_config * | cfg, | |
char * | catg, | |||
struct acf_odbc_query ** | query | |||
) | [static] |
Definition at line 636 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_strlen_zero(), ast_variable_retrieve(), dsn, errno, LOG_WARNING, OPT_ESCAPECOMMAS, OPT_MULTIROW, ast_custom_function::read, and ast_custom_function::synopsis.
Referenced by load_module(), and reload().
00637 { 00638 const char *tmp; 00639 int i; 00640 int res; 00641 00642 if (!cfg || !catg) { 00643 return EINVAL; 00644 } 00645 00646 *query = ast_calloc(1, sizeof(struct acf_odbc_query)); 00647 if (! (*query)) 00648 return ENOMEM; 00649 00650 if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) { 00651 char *tmp2 = ast_strdupa(tmp); 00652 AST_DECLARE_APP_ARGS(writeconf, 00653 AST_APP_ARG(dsn)[5]; 00654 ); 00655 AST_STANDARD_APP_ARGS(writeconf, tmp2); 00656 for (i = 0; i < 5; i++) { 00657 if (!ast_strlen_zero(writeconf.dsn[i])) 00658 ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i])); 00659 } 00660 } 00661 00662 if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) { 00663 char *tmp2 = ast_strdupa(tmp); 00664 AST_DECLARE_APP_ARGS(readconf, 00665 AST_APP_ARG(dsn)[5]; 00666 ); 00667 AST_STANDARD_APP_ARGS(readconf, tmp2); 00668 for (i = 0; i < 5; i++) { 00669 if (!ast_strlen_zero(readconf.dsn[i])) 00670 ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i])); 00671 } 00672 } else { 00673 /* If no separate readhandle, then use the writehandle for reading */ 00674 for (i = 0; i < 5; i++) { 00675 if (!ast_strlen_zero((*query)->writehandle[i])) 00676 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i])); 00677 } 00678 } 00679 00680 if ((tmp = ast_variable_retrieve(cfg, catg, "readsql"))) 00681 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00682 else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { 00683 ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); 00684 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00685 } 00686 00687 if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) { 00688 ast_free(*query); 00689 *query = NULL; 00690 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg); 00691 return EINVAL; 00692 } 00693 00694 if ((tmp = ast_variable_retrieve(cfg, catg, "writesql"))) 00695 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00696 else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { 00697 ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); 00698 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00699 } 00700 00701 if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) { 00702 ast_free(*query); 00703 *query = NULL; 00704 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg); 00705 return EINVAL; 00706 } 00707 00708 /* Allow escaping of embedded commas in fields to be turned off */ 00709 ast_set_flag((*query), OPT_ESCAPECOMMAS); 00710 if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) { 00711 if (ast_false(tmp)) 00712 ast_clear_flag((*query), OPT_ESCAPECOMMAS); 00713 } 00714 00715 if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) { 00716 if (strcasecmp(tmp, "multirow") == 0) 00717 ast_set_flag((*query), OPT_MULTIROW); 00718 if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit"))) 00719 sscanf(tmp, "%30d", &((*query)->rowlimit)); 00720 } 00721 00722 (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function)); 00723 if (! (*query)->acf) { 00724 ast_free(*query); 00725 *query = NULL; 00726 return ENOMEM; 00727 } 00728 00729 if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { 00730 if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) { 00731 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00732 } 00733 } else { 00734 if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) { 00735 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00736 } 00737 } 00738 00739 if (!((*query)->acf->name)) { 00740 ast_free((*query)->acf); 00741 ast_free(*query); 00742 *query = NULL; 00743 return ENOMEM; 00744 } 00745 00746 if (asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name) < 0) { 00747 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00748 (*query)->acf->syntax = NULL; 00749 } 00750 00751 if (!((*query)->acf->syntax)) { 00752 ast_free((char *)(*query)->acf->name); 00753 ast_free((*query)->acf); 00754 ast_free(*query); 00755 *query = NULL; 00756 return ENOMEM; 00757 } 00758 00759 (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; 00760 00761 res = 0; 00762 if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { 00763 res = asprintf((char **)&((*query)->acf->desc), 00764 "Runs the following query, as defined in func_odbc.conf, performing\n" 00765 "substitution of the arguments into the query as specified by ${ARG1},\n" 00766 "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" 00767 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00768 "\nRead:\n%s\n\nWrite:\n%s\n", 00769 (*query)->sql_read, 00770 (*query)->sql_write); 00771 } else if (!ast_strlen_zero((*query)->sql_read)) { 00772 res = asprintf((char **)&((*query)->acf->desc), 00773 "Runs the following query, as defined in func_odbc.conf, performing\n" 00774 "substitution of the arguments into the query as specified by ${ARG1},\n" 00775 "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", 00776 (*query)->sql_read); 00777 } else if (!ast_strlen_zero((*query)->sql_write)) { 00778 res = asprintf((char **)&((*query)->acf->desc), 00779 "Runs the following query, as defined in func_odbc.conf, performing\n" 00780 "substitution of the arguments into the query as specified by ${ARG1},\n" 00781 "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" 00782 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00783 "This function may only be set.\nSQL:\n%s\n", 00784 (*query)->sql_write); 00785 } else { 00786 ast_free((char *)(*query)->acf->syntax); 00787 ast_free((char *)(*query)->acf->name); 00788 ast_free((*query)->acf); 00789 ast_free(*query); 00790 ast_log(LOG_WARNING, "Section %s was found, but there was no SQL to execute. Ignoring.\n", catg); 00791 return EINVAL; 00792 } 00793 00794 if (res < 0) { 00795 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00796 (*query)->acf->desc = NULL; 00797 } 00798 00799 00800 if (!((*query)->acf->desc)) { 00801 ast_free((char *)(*query)->acf->syntax); 00802 ast_free((char *)(*query)->acf->name); 00803 ast_free((*query)->acf); 00804 ast_free(*query); 00805 *query = NULL; 00806 return ENOMEM; 00807 } 00808 00809 if (ast_strlen_zero((*query)->sql_read)) { 00810 (*query)->acf->read = NULL; 00811 } else { 00812 (*query)->acf->read = acf_odbc_read; 00813 } 00814 00815 if (ast_strlen_zero((*query)->sql_write)) { 00816 (*query)->acf->write = NULL; 00817 } else { 00818 (*query)->acf->write = acf_odbc_write; 00819 } 00820 00821 return 0; 00822 }
static int load_module | ( | void | ) | [static] |
Definition at line 841 of file func_odbc.c.
References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, config_flags, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), and LOG_NOTICE.
00842 { 00843 int res = 0; 00844 struct ast_config *cfg; 00845 char *catg; 00846 struct ast_flags config_flags = { 0 }; 00847 00848 res |= ast_custom_function_register(&fetch_function); 00849 res |= ast_register_application(app_odbcfinish, exec_odbcfinish, syn_odbcfinish, desc_odbcfinish); 00850 AST_RWLIST_WRLOCK(&queries); 00851 00852 cfg = ast_config_load(config, config_flags); 00853 if (!cfg) { 00854 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); 00855 AST_RWLIST_UNLOCK(&queries); 00856 return AST_MODULE_LOAD_DECLINE; 00857 } 00858 00859 for (catg = ast_category_browse(cfg, NULL); 00860 catg; 00861 catg = ast_category_browse(cfg, catg)) { 00862 struct acf_odbc_query *query = NULL; 00863 int err; 00864 00865 if ((err = init_acf_query(cfg, catg, &query))) { 00866 if (err == ENOMEM) 00867 ast_log(LOG_ERROR, "Out of memory\n"); 00868 else if (err == EINVAL) 00869 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg); 00870 else 00871 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err); 00872 } else { 00873 AST_RWLIST_INSERT_HEAD(&queries, query, list); 00874 ast_custom_function_register(query->acf); 00875 } 00876 } 00877 00878 ast_config_destroy(cfg); 00879 res |= ast_custom_function_register(&escape_function); 00880 00881 AST_RWLIST_UNLOCK(&queries); 00882 return res; 00883 }
static void odbc_datastore_free | ( | void * | data | ) | [static] |
Definition at line 91 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.
00092 { 00093 struct odbc_datastore *result = data; 00094 struct odbc_datastore_row *row; 00095 AST_LIST_LOCK(result); 00096 while ((row = AST_LIST_REMOVE_HEAD(result, list))) { 00097 ast_free(row); 00098 } 00099 AST_LIST_UNLOCK(result); 00100 AST_LIST_HEAD_DESTROY(result); 00101 ast_free(result); 00102 }
static int reload | ( | void | ) | [static] |
Definition at line 910 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_FILEUNCHANGED, free_acf_query(), init_acf_query(), and LOG_WARNING.
00911 { 00912 int res = 0; 00913 struct ast_config *cfg; 00914 struct acf_odbc_query *oldquery; 00915 char *catg; 00916 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; 00917 00918 cfg = ast_config_load(config, config_flags); 00919 if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00920 return 0; 00921 00922 AST_RWLIST_WRLOCK(&queries); 00923 00924 while (!AST_RWLIST_EMPTY(&queries)) { 00925 oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list); 00926 ast_custom_function_unregister(oldquery->acf); 00927 free_acf_query(oldquery); 00928 } 00929 00930 if (!cfg) { 00931 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); 00932 goto reload_out; 00933 } 00934 00935 for (catg = ast_category_browse(cfg, NULL); 00936 catg; 00937 catg = ast_category_browse(cfg, catg)) { 00938 struct acf_odbc_query *query = NULL; 00939 00940 if (init_acf_query(cfg, catg, &query)) { 00941 ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); 00942 } else { 00943 AST_RWLIST_INSERT_HEAD(&queries, query, list); 00944 ast_custom_function_register(query->acf); 00945 } 00946 } 00947 00948 ast_config_destroy(cfg); 00949 reload_out: 00950 AST_RWLIST_UNLOCK(&queries); 00951 return res; 00952 }
static int unload_module | ( | void | ) | [static] |
Definition at line 885 of file func_odbc.c.
References acf_odbc_query::acf, ast_custom_function_unregister(), AST_RWLIST_EMPTY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_unregister_application(), escape_function, fetch_function, free_acf_query(), and acf_odbc_query::list.
00886 { 00887 struct acf_odbc_query *query; 00888 int res = 0; 00889 00890 AST_RWLIST_WRLOCK(&queries); 00891 while (!AST_RWLIST_EMPTY(&queries)) { 00892 query = AST_RWLIST_REMOVE_HEAD(&queries, list); 00893 ast_custom_function_unregister(query->acf); 00894 free_acf_query(query); 00895 } 00896 00897 res |= ast_custom_function_unregister(&escape_function); 00898 res |= ast_custom_function_unregister(&fetch_function); 00899 res |= ast_unregister_application(app_odbcfinish); 00900 00901 /* Allow any threads waiting for this lock to pass (avoids a race) */ 00902 AST_RWLIST_UNLOCK(&queries); 00903 usleep(1); 00904 AST_RWLIST_WRLOCK(&queries); 00905 00906 AST_RWLIST_UNLOCK(&queries); 00907 return 0; 00908 }
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 960 of file func_odbc.c.
char* app_odbcfinish = "ODBCFinish" [static] |
Definition at line 619 of file func_odbc.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 960 of file func_odbc.c.
struct ast_threadstorage coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , } [static] |
Definition at line 88 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 47 of file func_odbc.c.
char* desc_odbcfinish [static] |
Initial value:
"ODBCFinish(<result-id>)\n" " Clears any remaining rows of the specified resultset\n"
Definition at line 621 of file func_odbc.c.
struct ast_custom_function escape_function [static] |
struct ast_custom_function fetch_function [static] |
struct ast_datastore_info odbc_info |
Initial value:
{ .type = "FUNC_ODBC", .destroy = odbc_datastore_free, }
Definition at line 67 of file func_odbc.c.
Referenced by acf_fetch(), and exec_odbcfinish().
enum { ... } odbc_option_flags |
int resultcount = 0 [static] |
Definition at line 86 of file func_odbc.c.
char* syn_odbcfinish = "Clear the resultset of a successful multirow query" [static] |
Definition at line 620 of file func_odbc.c.