ODBC lookups. More...
#include "asterisk.h"#include "asterisk/module.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/config.h"#include "asterisk/res_odbc.h"#include "asterisk/app.h"
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 |
| struct 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" |
ODBC lookups.
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] |
Definition at line 88 of file func_odbc.c.
| static void __init_colnames_buf | ( | void | ) | [static] |
Definition at line 89 of file func_odbc.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 955 of file func_odbc.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 955 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 549 of file func_odbc.c.
| static int acf_fetch | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 577 of file func_odbc.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_copy_string(), ast_datastore_free(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, odbc_datastore_row::data, ast_datastore::data, acf_odbc_query::list, odbc_datastore::names, odbc_info, and pbx_builtin_setvar_helper().
00578 { 00579 struct ast_datastore *store; 00580 struct odbc_datastore *resultset; 00581 struct odbc_datastore_row *row; 00582 store = ast_channel_datastore_find(chan, &odbc_info, data); 00583 if (!store) { 00584 return -1; 00585 } 00586 resultset = store->data; 00587 AST_LIST_LOCK(resultset); 00588 row = AST_LIST_REMOVE_HEAD(resultset, list); 00589 AST_LIST_UNLOCK(resultset); 00590 if (!row) { 00591 /* Cleanup datastore */ 00592 ast_channel_datastore_remove(chan, store); 00593 ast_datastore_free(store); 00594 return -1; 00595 } 00596 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names); 00597 ast_copy_string(buf, row->data, len); 00598 ast_free(row); 00599 return 0; 00600 }
| 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_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_alloc, ast_channel_datastore_add(), ast_channel_free(), ast_copy_string(), ast_datastore_alloc, ast_debug, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj(), ast_realloc, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_create(), ast_str_make_space(), ast_str_reset(), ast_str_thread_get(), ast_strlen_zero(), ast_test_flag, ast_verb, coldata_buf, colnames_buf, ast_datastore::data, dsn, generic_execute(), ast_str::len, acf_odbc_query::list, LOG_ERROR, LOG_WARNING, ast_custom_function::name, odbc_datastore_free(), odbc_info, OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), acf_odbc_query::readhandle, resultcount, acf_odbc_query::rowlimit, acf_odbc_query::sql_read, ast_str::str, and ast_str::used.
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 buf[0] = '\0'; 00395 for (x = 0; x < colcount; x++) { 00396 int i; 00397 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16); 00398 00399 if (y == 0) { 00400 char colname[256]; 00401 SQLULEN maxcol; 00402 00403 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL); 00404 ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x); 00405 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { 00406 snprintf(colname, sizeof(colname), "field%d", x); 00407 } 00408 00409 if (coldata->len < maxcol + 1) { 00410 ast_str_make_space(&coldata, maxcol + 1); 00411 } 00412 00413 if (colnames->used) { 00414 ast_str_append(&colnames, 0, ","); 00415 } 00416 ast_str_make_space(&colnames, strlen(colname) * 2 + 1 + colnames->used); 00417 00418 /* Copy data, encoding '\' and ',' for the argument parser */ 00419 for (i = 0; i < sizeof(colname); i++) { 00420 if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) { 00421 colnames->str[colnames->used++] = '\\'; 00422 } 00423 colnames->str[colnames->used++] = colname[i]; 00424 00425 if (colname[i] == '\0') { 00426 colnames->used--; 00427 break; 00428 } 00429 } 00430 00431 if (resultset) { 00432 void *tmp = ast_realloc(resultset, sizeof(*resultset) + colnames->used + 1); 00433 if (!tmp) { 00434 ast_log(LOG_ERROR, "No space for a new resultset?\n"); 00435 ast_free(resultset); 00436 SQLCloseCursor(stmt); 00437 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00438 ast_odbc_release_obj(obj); 00439 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00440 if (chan) 00441 ast_autoservice_stop(chan); 00442 if (bogus_chan) 00443 ast_channel_free(chan); 00444 ast_free(sql); 00445 return -1; 00446 } 00447 resultset = tmp; 00448 strcpy((char *)resultset + sizeof(*resultset), colnames->str); 00449 } 00450 } 00451 00452 buflen = strlen(buf); 00453 res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata->str, coldata->len, &indicator); 00454 if (indicator == SQL_NULL_DATA) { 00455 ast_debug(3, "Got NULL data\n"); 00456 ast_str_reset(coldata); 00457 res = SQL_SUCCESS; 00458 } 00459 00460 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00461 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql->str); 00462 y = -1; 00463 buf[0] = '\0'; 00464 goto end_acf_read; 00465 } 00466 00467 ast_debug(2, "Got coldata of '%s'\n", coldata->str); 00468 coldata->used = strlen(coldata->str); 00469 00470 /* Copy data, encoding '\' and ',' for the argument parser */ 00471 for (i = 0; i < coldata->used; i++) { 00472 if (escapecommas && (coldata->str[i] == '\\' || coldata->str[i] == ',')) { 00473 buf[buflen++] = '\\'; 00474 } 00475 buf[buflen++] = coldata->str[i]; 00476 00477 if (buflen >= len - 2) 00478 break; 00479 00480 if (coldata->str[i] == '\0') 00481 break; 00482 } 00483 00484 buf[buflen++] = ','; 00485 buf[buflen] = '\0'; 00486 ast_debug(2, "buf is now set to '%s'\n", buf); 00487 } 00488 /* Trim trailing comma */ 00489 buf[buflen - 1] = '\0'; 00490 ast_debug(2, "buf is now set to '%s'\n", buf); 00491 00492 if (resultset) { 00493 row = ast_calloc(1, sizeof(*row) + buflen); 00494 if (!row) { 00495 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n"); 00496 goto end_acf_read; 00497 } 00498 strcpy((char *)row + sizeof(*row), buf); 00499 AST_LIST_INSERT_TAIL(resultset, row, list); 00500 00501 /* Get next row */ 00502 res = SQLFetch(stmt); 00503 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00504 if (res != SQL_NO_DATA) 00505 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str); 00506 y++; 00507 break; 00508 } 00509 } 00510 } 00511 00512 end_acf_read: 00513 snprintf(rowcount, sizeof(rowcount), "%d", y); 00514 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00515 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames->str); 00516 if (resultset) { 00517 int uid; 00518 struct ast_datastore *odbc_store; 00519 uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1; 00520 snprintf(buf, len, "%d", uid); 00521 odbc_store = ast_datastore_alloc(&odbc_info, buf); 00522 if (!odbc_store) { 00523 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n"); 00524 odbc_datastore_free(resultset); 00525 SQLCloseCursor(stmt); 00526 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00527 ast_odbc_release_obj(obj); 00528 if (chan) 00529 ast_autoservice_stop(chan); 00530 if (bogus_chan) 00531 ast_channel_free(chan); 00532 ast_free(sql); 00533 return -1; 00534 } 00535 odbc_store->data = resultset; 00536 ast_channel_datastore_add(chan, odbc_store); 00537 } 00538 SQLCloseCursor(stmt); 00539 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00540 ast_odbc_release_obj(obj); 00541 if (chan) 00542 ast_autoservice_stop(chan); 00543 if (bogus_chan) 00544 ast_channel_free(chan); 00545 ast_free(sql); 00546 return 0; 00547 }
| 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_release_obj(), 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, dsn, generic_execute(), ast_str::len, 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, ast_str::str, 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 621 of file func_odbc.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_datastore_free(), and odbc_info.
Referenced by load_module().
00622 { 00623 struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data); 00624 if (!store) /* Already freed; no big deal. */ 00625 return 0; 00626 ast_channel_datastore_remove(chan, store); 00627 ast_datastore_free(store); 00628 return 0; 00629 }
| static int free_acf_query | ( | struct acf_odbc_query * | query | ) | [static] |
Definition at line 819 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().
00820 { 00821 if (query) { 00822 if (query->acf) { 00823 if (query->acf->name) 00824 ast_free((char *)query->acf->name); 00825 if (query->acf->syntax) 00826 ast_free((char *)query->acf->syntax); 00827 if (query->acf->desc) 00828 ast_free((char *)query->acf->desc); 00829 ast_free(query->acf); 00830 } 00831 ast_free(query); 00832 } 00833 return 0; 00834 }
| 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 631 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_ERROR, LOG_WARNING, OPT_ESCAPECOMMAS, OPT_MULTIROW, ast_custom_function::read, and ast_custom_function::synopsis.
Referenced by load_module(), and reload().
00632 { 00633 const char *tmp; 00634 int i; 00635 int res; 00636 00637 if (!cfg || !catg) { 00638 return EINVAL; 00639 } 00640 00641 *query = ast_calloc(1, sizeof(struct acf_odbc_query)); 00642 if (! (*query)) 00643 return ENOMEM; 00644 00645 if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) { 00646 char *tmp2 = ast_strdupa(tmp); 00647 AST_DECLARE_APP_ARGS(writeconf, 00648 AST_APP_ARG(dsn)[5]; 00649 ); 00650 AST_STANDARD_APP_ARGS(writeconf, tmp2); 00651 for (i = 0; i < 5; i++) { 00652 if (!ast_strlen_zero(writeconf.dsn[i])) 00653 ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i])); 00654 } 00655 } 00656 00657 if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) { 00658 char *tmp2 = ast_strdupa(tmp); 00659 AST_DECLARE_APP_ARGS(readconf, 00660 AST_APP_ARG(dsn)[5]; 00661 ); 00662 AST_STANDARD_APP_ARGS(readconf, tmp2); 00663 for (i = 0; i < 5; i++) { 00664 if (!ast_strlen_zero(readconf.dsn[i])) 00665 ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i])); 00666 } 00667 } else { 00668 /* If no separate readhandle, then use the writehandle for reading */ 00669 for (i = 0; i < 5; i++) { 00670 if (!ast_strlen_zero((*query)->writehandle[i])) 00671 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i])); 00672 } 00673 } 00674 00675 if ((tmp = ast_variable_retrieve(cfg, catg, "readsql"))) 00676 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00677 else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { 00678 ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); 00679 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00680 } 00681 00682 if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) { 00683 ast_free(*query); 00684 *query = NULL; 00685 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg); 00686 return EINVAL; 00687 } 00688 00689 if ((tmp = ast_variable_retrieve(cfg, catg, "writesql"))) 00690 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00691 else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { 00692 ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); 00693 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00694 } 00695 00696 if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) { 00697 ast_free(*query); 00698 *query = NULL; 00699 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg); 00700 return EINVAL; 00701 } 00702 00703 /* Allow escaping of embedded commas in fields to be turned off */ 00704 ast_set_flag((*query), OPT_ESCAPECOMMAS); 00705 if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) { 00706 if (ast_false(tmp)) 00707 ast_clear_flag((*query), OPT_ESCAPECOMMAS); 00708 } 00709 00710 if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) { 00711 if (strcasecmp(tmp, "multirow") == 0) 00712 ast_set_flag((*query), OPT_MULTIROW); 00713 if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit"))) 00714 sscanf(tmp, "%30d", &((*query)->rowlimit)); 00715 } 00716 00717 (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function)); 00718 if (! (*query)->acf) { 00719 ast_free(*query); 00720 *query = NULL; 00721 return ENOMEM; 00722 } 00723 00724 if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { 00725 if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) { 00726 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00727 } 00728 } else { 00729 if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) { 00730 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00731 } 00732 } 00733 00734 if (!((*query)->acf->name)) { 00735 ast_free((*query)->acf); 00736 ast_free(*query); 00737 *query = NULL; 00738 return ENOMEM; 00739 } 00740 00741 if (asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name) < 0) { 00742 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00743 (*query)->acf->syntax = NULL; 00744 } 00745 00746 if (!((*query)->acf->syntax)) { 00747 ast_free((char *)(*query)->acf->name); 00748 ast_free((*query)->acf); 00749 ast_free(*query); 00750 *query = NULL; 00751 return ENOMEM; 00752 } 00753 00754 (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; 00755 00756 res = 0; 00757 if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { 00758 res = asprintf((char **)&((*query)->acf->desc), 00759 "Runs the following query, as defined in func_odbc.conf, performing\n" 00760 "substitution of the arguments into the query as specified by ${ARG1},\n" 00761 "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" 00762 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00763 "\nRead:\n%s\n\nWrite:\n%s\n", 00764 (*query)->sql_read, 00765 (*query)->sql_write); 00766 } else if (!ast_strlen_zero((*query)->sql_read)) { 00767 res = asprintf((char **)&((*query)->acf->desc), 00768 "Runs the following query, as defined in func_odbc.conf, performing\n" 00769 "substitution of the arguments into the query as specified by ${ARG1},\n" 00770 "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", 00771 (*query)->sql_read); 00772 } else if (!ast_strlen_zero((*query)->sql_write)) { 00773 res = asprintf((char **)&((*query)->acf->desc), 00774 "Runs the following query, as defined in func_odbc.conf, performing\n" 00775 "substitution of the arguments into the query as specified by ${ARG1},\n" 00776 "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" 00777 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00778 "This function may only be set.\nSQL:\n%s\n", 00779 (*query)->sql_write); 00780 } else { 00781 ast_free((char *)(*query)->acf->syntax); 00782 ast_free((char *)(*query)->acf->name); 00783 ast_free((*query)->acf); 00784 ast_free(*query); 00785 ast_log(LOG_WARNING, "Section %s was found, but there was no SQL to execute. Ignoring.\n", catg); 00786 return EINVAL; 00787 } 00788 00789 if (res < 0) { 00790 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00791 (*query)->acf->desc = NULL; 00792 } 00793 00794 00795 if (!((*query)->acf->desc)) { 00796 ast_free((char *)(*query)->acf->syntax); 00797 ast_free((char *)(*query)->acf->name); 00798 ast_free((*query)->acf); 00799 ast_free(*query); 00800 *query = NULL; 00801 return ENOMEM; 00802 } 00803 00804 if (ast_strlen_zero((*query)->sql_read)) { 00805 (*query)->acf->read = NULL; 00806 } else { 00807 (*query)->acf->read = acf_odbc_read; 00808 } 00809 00810 if (ast_strlen_zero((*query)->sql_write)) { 00811 (*query)->acf->write = NULL; 00812 } else { 00813 (*query)->acf->write = acf_odbc_write; 00814 } 00815 00816 return 0; 00817 }
| static int load_module | ( | void | ) | [static] |
Definition at line 836 of file func_odbc.c.
References acf_odbc_query::acf, app_odbcfinish, 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, desc_odbcfinish, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), acf_odbc_query::list, LOG_ERROR, LOG_NOTICE, and syn_odbcfinish.
00837 { 00838 int res = 0; 00839 struct ast_config *cfg; 00840 char *catg; 00841 struct ast_flags config_flags = { 0 }; 00842 00843 res |= ast_custom_function_register(&fetch_function); 00844 res |= ast_register_application(app_odbcfinish, exec_odbcfinish, syn_odbcfinish, desc_odbcfinish); 00845 AST_RWLIST_WRLOCK(&queries); 00846 00847 cfg = ast_config_load(config, config_flags); 00848 if (!cfg) { 00849 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); 00850 AST_RWLIST_UNLOCK(&queries); 00851 return AST_MODULE_LOAD_DECLINE; 00852 } 00853 00854 for (catg = ast_category_browse(cfg, NULL); 00855 catg; 00856 catg = ast_category_browse(cfg, catg)) { 00857 struct acf_odbc_query *query = NULL; 00858 int err; 00859 00860 if ((err = init_acf_query(cfg, catg, &query))) { 00861 if (err == ENOMEM) 00862 ast_log(LOG_ERROR, "Out of memory\n"); 00863 else if (err == EINVAL) 00864 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg); 00865 else 00866 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err); 00867 } else { 00868 AST_RWLIST_INSERT_HEAD(&queries, query, list); 00869 ast_custom_function_register(query->acf); 00870 } 00871 } 00872 00873 ast_config_destroy(cfg); 00874 res |= ast_custom_function_register(&escape_function); 00875 00876 AST_RWLIST_UNLOCK(&queries); 00877 return res; 00878 }
| 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.
Referenced by acf_odbc_read().
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 905 of file func_odbc.c.
References acf_odbc_query::acf, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_custom_function_unregister(), ast_log(), AST_RWLIST_EMPTY, AST_RWLIST_INSERT_HEAD, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, free_acf_query(), init_acf_query(), acf_odbc_query::list, LOG_ERROR, and LOG_WARNING.
00906 { 00907 int res = 0; 00908 struct ast_config *cfg; 00909 struct acf_odbc_query *oldquery; 00910 char *catg; 00911 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; 00912 00913 cfg = ast_config_load(config, config_flags); 00914 if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00915 return 0; 00916 00917 AST_RWLIST_WRLOCK(&queries); 00918 00919 while (!AST_RWLIST_EMPTY(&queries)) { 00920 oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list); 00921 ast_custom_function_unregister(oldquery->acf); 00922 free_acf_query(oldquery); 00923 } 00924 00925 if (!cfg) { 00926 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); 00927 goto reload_out; 00928 } 00929 00930 for (catg = ast_category_browse(cfg, NULL); 00931 catg; 00932 catg = ast_category_browse(cfg, catg)) { 00933 struct acf_odbc_query *query = NULL; 00934 00935 if (init_acf_query(cfg, catg, &query)) { 00936 ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); 00937 } else { 00938 AST_RWLIST_INSERT_HEAD(&queries, query, list); 00939 ast_custom_function_register(query->acf); 00940 } 00941 } 00942 00943 ast_config_destroy(cfg); 00944 reload_out: 00945 AST_RWLIST_UNLOCK(&queries); 00946 return res; 00947 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 880 of file func_odbc.c.
References acf_odbc_query::acf, app_odbcfinish, 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.
00881 { 00882 struct acf_odbc_query *query; 00883 int res = 0; 00884 00885 AST_RWLIST_WRLOCK(&queries); 00886 while (!AST_RWLIST_EMPTY(&queries)) { 00887 query = AST_RWLIST_REMOVE_HEAD(&queries, list); 00888 ast_custom_function_unregister(query->acf); 00889 free_acf_query(query); 00890 } 00891 00892 res |= ast_custom_function_unregister(&escape_function); 00893 res |= ast_custom_function_unregister(&fetch_function); 00894 res |= ast_unregister_application(app_odbcfinish); 00895 00896 /* Allow any threads waiting for this lock to pass (avoids a race) */ 00897 AST_RWLIST_UNLOCK(&queries); 00898 usleep(1); 00899 AST_RWLIST_WRLOCK(&queries); 00900 00901 AST_RWLIST_UNLOCK(&queries); 00902 return 0; 00903 }
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 955 of file func_odbc.c.
char* app_odbcfinish = "ODBCFinish" [static] |
Definition at line 614 of file func_odbc.c.
Referenced by load_module(), and unload_module().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 955 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.
Referenced by acf_odbc_read().
struct ast_threadstorage colnames_buf = { .once = PTHREAD_ONCE_INIT, .key_init = __init_colnames_buf , .custom_init = NULL , } [static] |
Definition at line 89 of file func_odbc.c.
Referenced by acf_odbc_read().
char* config = "func_odbc.conf" [static] |
Definition at line 47 of file func_odbc.c.
char* desc_odbcfinish [static] |
"ODBCFinish(<result-id>)\n" " Clears any remaining rows of the specified resultset\n"
Definition at line 616 of file func_odbc.c.
Referenced by load_module().
struct ast_custom_function escape_function [static] |
Definition at line 565 of file func_odbc.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function fetch_function [static] |
Definition at line 602 of file func_odbc.c.
Referenced by load_module(), and unload_module().
| struct ast_datastore_info odbc_info |
{
.type = "FUNC_ODBC",
.destroy = odbc_datastore_free,
}
Definition at line 67 of file func_odbc.c.
Referenced by acf_fetch(), acf_odbc_read(), and exec_odbcfinish().
| enum { ... } odbc_option_flags |
int resultcount = 0 [static] |
Definition at line 86 of file func_odbc.c.
Referenced by acf_odbc_read().
char* syn_odbcfinish = "Clear the resultset of a successful multirow query" [static] |
Definition at line 615 of file func_odbc.c.
Referenced by load_module().
1.6.1