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