#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 | __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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } |
static char * | app_odbcfinish = "ODBCFinish" |
static const struct ast_module_info * | ast_module_info = &__mod_info |
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 __reg_module | ( | void | ) | [static] |
Definition at line 915 of file func_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 915 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 509 of file func_odbc.c.
00510 { 00511 char *out = buf; 00512 00513 for (; *data && out - buf < len; data++) { 00514 if (*data == '\'') { 00515 *out = '\''; 00516 out++; 00517 } 00518 *out++ = *data; 00519 } 00520 *out = '\0'; 00521 00522 return 0; 00523 }
static int acf_fetch | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 537 of file func_odbc.c.
References ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_copy_string(), 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().
00538 { 00539 struct ast_datastore *store; 00540 struct odbc_datastore *resultset; 00541 struct odbc_datastore_row *row; 00542 store = ast_channel_datastore_find(chan, &odbc_info, data); 00543 if (!store) { 00544 return -1; 00545 } 00546 resultset = store->data; 00547 AST_LIST_LOCK(resultset); 00548 row = AST_LIST_REMOVE_HEAD(resultset, list); 00549 AST_LIST_UNLOCK(resultset); 00550 if (!row) { 00551 /* Cleanup datastore */ 00552 ast_channel_datastore_remove(chan, store); 00553 ast_channel_datastore_free(store); 00554 return -1; 00555 } 00556 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names); 00557 ast_copy_string(buf, row->data, len); 00558 ast_free(row); 00559 return 0; 00560 }
static int acf_odbc_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | s, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 245 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_LIST_HEAD_INIT, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_test_flag, chan, 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, and acf_odbc_query::sql_read.
Referenced by init_acf_query().
00246 { 00247 struct odbc_obj *obj = NULL; 00248 struct acf_odbc_query *query; 00249 char sql[2048], varname[15], colnames[2048] = "", rowcount[12] = "-1"; 00250 int res, x, y, buflen = 0, escapecommas, rowlimit = 1, dsn, bogus_chan = 0; 00251 AST_DECLARE_APP_ARGS(args, 00252 AST_APP_ARG(field)[100]; 00253 ); 00254 SQLHSTMT stmt = NULL; 00255 SQLSMALLINT colcount=0; 00256 SQLLEN indicator; 00257 SQLSMALLINT collength; 00258 struct odbc_datastore *resultset = NULL; 00259 struct odbc_datastore_row *row = NULL; 00260 00261 AST_LIST_LOCK(&queries); 00262 AST_LIST_TRAVERSE(&queries, query, list) { 00263 if (!strcmp(query->acf->name, cmd)) { 00264 break; 00265 } 00266 } 00267 00268 if (!query) { 00269 ast_log(LOG_ERROR, "No such function '%s'\n", cmd); 00270 AST_LIST_UNLOCK(&queries); 00271 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00272 return -1; 00273 } 00274 00275 if (!chan) { 00276 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) 00277 bogus_chan = 1; 00278 } 00279 00280 if (chan) 00281 ast_autoservice_start(chan); 00282 00283 AST_STANDARD_APP_ARGS(args, s); 00284 for (x = 0; x < args.argc; x++) { 00285 snprintf(varname, sizeof(varname), "ARG%d", x + 1); 00286 pbx_builtin_pushvar_helper(chan, varname, args.field[x]); 00287 } 00288 00289 pbx_substitute_variables_helper(chan, query->sql_read, sql, sizeof(sql) - 1); 00290 00291 /* Restore prior values */ 00292 for (x = 0; x < args.argc; x++) { 00293 snprintf(varname, sizeof(varname), "ARG%d", x + 1); 00294 pbx_builtin_setvar_helper(chan, varname, NULL); 00295 } 00296 00297 /* Save these flags, so we can release the lock */ 00298 escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS); 00299 if (ast_test_flag(query, OPT_MULTIROW)) { 00300 resultset = ast_calloc(1, sizeof(*resultset)); 00301 AST_LIST_HEAD_INIT(resultset); 00302 if (query->rowlimit) 00303 rowlimit = query->rowlimit; 00304 else 00305 rowlimit = INT_MAX; 00306 } 00307 AST_LIST_UNLOCK(&queries); 00308 00309 for (dsn = 0; dsn < 5; dsn++) { 00310 if (!ast_strlen_zero(query->readhandle[dsn])) { 00311 obj = ast_odbc_request_obj(query->readhandle[dsn], 0); 00312 if (obj) 00313 stmt = ast_odbc_direct_execute(obj, generic_execute, sql); 00314 } 00315 if (stmt) 00316 break; 00317 } 00318 00319 if (!stmt) { 00320 ast_log(LOG_ERROR, "Unable to execute query [%s]\n", sql); 00321 if (obj) 00322 ast_odbc_release_obj(obj); 00323 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00324 if (chan) 00325 ast_autoservice_stop(chan); 00326 if (bogus_chan) 00327 ast_channel_free(chan); 00328 return -1; 00329 } 00330 00331 res = SQLNumResultCols(stmt, &colcount); 00332 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00333 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); 00334 SQLCloseCursor(stmt); 00335 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00336 ast_odbc_release_obj(obj); 00337 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00338 if (chan) 00339 ast_autoservice_stop(chan); 00340 if (bogus_chan) 00341 ast_channel_free(chan); 00342 return -1; 00343 } 00344 00345 res = SQLFetch(stmt); 00346 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00347 int res1 = -1; 00348 if (res == SQL_NO_DATA) { 00349 ast_verb(4, "Found no rows [%s]\n", sql); 00350 res1 = 0; 00351 ast_copy_string(rowcount, "0", sizeof(rowcount)); 00352 } else { 00353 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql); 00354 } 00355 SQLCloseCursor(stmt); 00356 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00357 ast_odbc_release_obj(obj); 00358 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00359 if (chan) 00360 ast_autoservice_stop(chan); 00361 if (bogus_chan) 00362 ast_channel_free(chan); 00363 return res1; 00364 } 00365 00366 for (y = 0; y < rowlimit; y++) { 00367 *buf = '\0'; 00368 for (x = 0; x < colcount; x++) { 00369 int i; 00370 char coldata[256]; 00371 00372 if (y == 0) { 00373 char colname[256]; 00374 int namelen; 00375 00376 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL); 00377 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { 00378 snprintf(colname, sizeof(colname), "field%d", x); 00379 } 00380 00381 if (!ast_strlen_zero(colnames)) 00382 strncat(colnames, ",", sizeof(colnames) - strlen(colnames) - 1); 00383 namelen = strlen(colnames); 00384 00385 /* Copy data, encoding '\' and ',' for the argument parser */ 00386 for (i = 0; i < sizeof(colname); i++) { 00387 if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) { 00388 colnames[namelen++] = '\\'; 00389 } 00390 colnames[namelen++] = colname[i]; 00391 00392 if (namelen >= sizeof(colnames) - 2) { 00393 colnames[namelen >= sizeof(colnames) ? sizeof(colnames) - 1 : namelen] = '\0'; 00394 break; 00395 } 00396 00397 if (colname[i] == '\0') 00398 break; 00399 } 00400 00401 if (resultset) { 00402 void *tmp = ast_realloc(resultset, sizeof(*resultset) + strlen(colnames) + 1); 00403 if (!tmp) { 00404 ast_log(LOG_ERROR, "No space for a new resultset?\n"); 00405 ast_free(resultset); 00406 SQLCloseCursor(stmt); 00407 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00408 ast_odbc_release_obj(obj); 00409 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00410 if (chan) 00411 ast_autoservice_stop(chan); 00412 if (bogus_chan) 00413 ast_channel_free(chan); 00414 return -1; 00415 } 00416 resultset = tmp; 00417 strcpy((char *)resultset + sizeof(*resultset), colnames); 00418 } 00419 } 00420 00421 buflen = strlen(buf); 00422 res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata, sizeof(coldata), &indicator); 00423 if (indicator == SQL_NULL_DATA) { 00424 coldata[0] = '\0'; 00425 res = SQL_SUCCESS; 00426 } 00427 00428 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00429 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); 00430 y = -1; 00431 goto end_acf_read; 00432 } 00433 00434 /* Copy data, encoding '\' and ',' for the argument parser */ 00435 for (i = 0; i < sizeof(coldata); i++) { 00436 if (escapecommas && (coldata[i] == '\\' || coldata[i] == ',')) { 00437 buf[buflen++] = '\\'; 00438 } 00439 buf[buflen++] = coldata[i]; 00440 00441 if (buflen >= len - 2) 00442 break; 00443 00444 if (coldata[i] == '\0') 00445 break; 00446 } 00447 00448 buf[buflen - 1] = ','; 00449 buf[buflen] = '\0'; 00450 } 00451 /* Trim trailing comma */ 00452 buf[buflen - 1] = '\0'; 00453 00454 if (resultset) { 00455 row = ast_calloc(1, sizeof(*row) + buflen); 00456 if (!row) { 00457 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n"); 00458 goto end_acf_read; 00459 } 00460 strcpy((char *)row + sizeof(*row), buf); 00461 AST_LIST_INSERT_TAIL(resultset, row, list); 00462 00463 /* Get next row */ 00464 res = SQLFetch(stmt); 00465 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00466 if (res != SQL_NO_DATA) 00467 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql); 00468 y++; 00469 break; 00470 } 00471 } 00472 } 00473 00474 end_acf_read: 00475 snprintf(rowcount, sizeof(rowcount), "%d", y); 00476 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); 00477 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames); 00478 if (resultset) { 00479 int uid; 00480 struct ast_datastore *odbc_store; 00481 uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1; 00482 snprintf(buf, len, "%d", uid); 00483 odbc_store = ast_channel_datastore_alloc(&odbc_info, buf); 00484 if (!odbc_store) { 00485 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n"); 00486 odbc_datastore_free(resultset); 00487 SQLCloseCursor(stmt); 00488 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00489 ast_odbc_release_obj(obj); 00490 if (chan) 00491 ast_autoservice_stop(chan); 00492 if (bogus_chan) 00493 ast_channel_free(chan); 00494 return -1; 00495 } 00496 odbc_store->data = resultset; 00497 ast_channel_datastore_add(chan, odbc_store); 00498 } 00499 SQLCloseCursor(stmt); 00500 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00501 ast_odbc_release_obj(obj); 00502 if (chan) 00503 ast_autoservice_stop(chan); 00504 if (bogus_chan) 00505 ast_channel_free(chan); 00506 return 0; 00507 }
static int acf_odbc_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | s, | |||
const char * | value | |||
) | [static] |
Definition at line 127 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_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_odbc_direct_execute(), ast_odbc_request_obj(), AST_STANDARD_APP_ARGS, 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().
00128 { 00129 struct odbc_obj *obj = NULL; 00130 struct acf_odbc_query *query; 00131 char *t, buf[2048], varname[15]; 00132 int i, dsn, bogus_chan = 0; 00133 AST_DECLARE_APP_ARGS(values, 00134 AST_APP_ARG(field)[100]; 00135 ); 00136 AST_DECLARE_APP_ARGS(args, 00137 AST_APP_ARG(field)[100]; 00138 ); 00139 SQLHSTMT stmt = NULL; 00140 SQLLEN rows=0; 00141 00142 AST_LIST_LOCK(&queries); 00143 AST_LIST_TRAVERSE(&queries, query, list) { 00144 if (!strcmp(query->acf->name, cmd)) { 00145 break; 00146 } 00147 } 00148 00149 if (!query) { 00150 ast_log(LOG_ERROR, "No such function '%s'\n", cmd); 00151 AST_LIST_UNLOCK(&queries); 00152 return -1; 00153 } 00154 00155 if (!chan) { 00156 if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) 00157 bogus_chan = 1; 00158 } 00159 00160 if (chan) 00161 ast_autoservice_start(chan); 00162 00163 /* Parse our arguments */ 00164 t = value ? ast_strdupa(value) : ""; 00165 00166 if (!s || !t) { 00167 ast_log(LOG_ERROR, "Out of memory\n"); 00168 AST_LIST_UNLOCK(&queries); 00169 if (chan) 00170 ast_autoservice_stop(chan); 00171 if (bogus_chan) 00172 ast_channel_free(chan); 00173 return -1; 00174 } 00175 00176 AST_STANDARD_APP_ARGS(args, s); 00177 for (i = 0; i < args.argc; i++) { 00178 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 00179 pbx_builtin_pushvar_helper(chan, varname, args.field[i]); 00180 } 00181 00182 /* Parse values, just like arguments */ 00183 AST_STANDARD_APP_ARGS(values, t); 00184 for (i = 0; i < values.argc; i++) { 00185 snprintf(varname, sizeof(varname), "VAL%d", i + 1); 00186 pbx_builtin_pushvar_helper(chan, varname, values.field[i]); 00187 } 00188 00189 /* Additionally set the value as a whole (but push an empty string if value is NULL) */ 00190 pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : ""); 00191 00192 pbx_substitute_variables_helper(chan, query->sql_write, buf, sizeof(buf) - 1); 00193 00194 /* Restore prior values */ 00195 for (i = 0; i < args.argc; i++) { 00196 snprintf(varname, sizeof(varname), "ARG%d", i + 1); 00197 pbx_builtin_setvar_helper(chan, varname, NULL); 00198 } 00199 00200 for (i = 0; i < values.argc; i++) { 00201 snprintf(varname, sizeof(varname), "VAL%d", i + 1); 00202 pbx_builtin_setvar_helper(chan, varname, NULL); 00203 } 00204 pbx_builtin_setvar_helper(chan, "VALUE", NULL); 00205 00206 AST_LIST_UNLOCK(&queries); 00207 00208 for (dsn = 0; dsn < 5; dsn++) { 00209 if (!ast_strlen_zero(query->writehandle[dsn])) { 00210 obj = ast_odbc_request_obj(query->writehandle[dsn], 0); 00211 if (obj) 00212 stmt = ast_odbc_direct_execute(obj, generic_execute, buf); 00213 } 00214 if (stmt) 00215 break; 00216 } 00217 00218 if (stmt) { 00219 /* Rows affected */ 00220 SQLRowCount(stmt, &rows); 00221 } 00222 00223 /* Output the affected rows, for all cases. In the event of failure, we 00224 * flag this as -1 rows. Note that this is different from 0 affected rows 00225 * which would be the case if we succeeded in our query, but the values did 00226 * not change. */ 00227 snprintf(varname, sizeof(varname), "%d", (int)rows); 00228 pbx_builtin_setvar_helper(chan, "ODBCROWS", varname); 00229 00230 if (stmt) { 00231 SQLCloseCursor(stmt); 00232 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00233 } 00234 if (obj) 00235 ast_odbc_release_obj(obj); 00236 00237 if (chan) 00238 ast_autoservice_stop(chan); 00239 if (bogus_chan) 00240 ast_channel_free(chan); 00241 00242 return 0; 00243 }
static int exec_odbcfinish | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 581 of file func_odbc.c.
References ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), chan, and odbc_info.
Referenced by load_module().
00582 { 00583 struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data); 00584 if (!store) /* Already freed; no big deal. */ 00585 return 0; 00586 ast_channel_datastore_remove(chan, store); 00587 ast_channel_datastore_free(store); 00588 return 0; 00589 }
static int free_acf_query | ( | struct acf_odbc_query * | query | ) | [static] |
Definition at line 779 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().
00780 { 00781 if (query) { 00782 if (query->acf) { 00783 if (query->acf->name) 00784 ast_free((char *)query->acf->name); 00785 if (query->acf->syntax) 00786 ast_free((char *)query->acf->syntax); 00787 if (query->acf->desc) 00788 ast_free((char *)query->acf->desc); 00789 ast_free(query->acf); 00790 } 00791 ast_free(query); 00792 } 00793 return 0; 00794 }
static SQLHSTMT generic_execute | ( | struct odbc_obj * | obj, | |
void * | data | |||
) | [static] |
Definition at line 101 of file func_odbc.c.
References ast_log(), odbc_obj::con, and LOG_WARNING.
Referenced by acf_odbc_read(), and acf_odbc_write().
00102 { 00103 int res; 00104 char *sql = data; 00105 SQLHSTMT stmt; 00106 00107 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); 00108 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00109 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00110 return NULL; 00111 } 00112 00113 res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS); 00114 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00115 ast_log(LOG_WARNING, "SQL Exec Direct failed![%s]\n", sql); 00116 SQLCloseCursor(stmt); 00117 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00118 return NULL; 00119 } 00120 00121 return stmt; 00122 }
static int init_acf_query | ( | struct ast_config * | cfg, | |
char * | catg, | |||
struct acf_odbc_query ** | query | |||
) | [static] |
Definition at line 591 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().
00592 { 00593 const char *tmp; 00594 int i; 00595 int res; 00596 00597 if (!cfg || !catg) { 00598 return EINVAL; 00599 } 00600 00601 *query = ast_calloc(1, sizeof(struct acf_odbc_query)); 00602 if (! (*query)) 00603 return ENOMEM; 00604 00605 if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) { 00606 char *tmp2 = ast_strdupa(tmp); 00607 AST_DECLARE_APP_ARGS(write, 00608 AST_APP_ARG(dsn)[5]; 00609 ); 00610 AST_STANDARD_APP_ARGS(write, tmp2); 00611 for (i = 0; i < 5; i++) { 00612 if (!ast_strlen_zero(write.dsn[i])) 00613 ast_copy_string((*query)->writehandle[i], write.dsn[i], sizeof((*query)->writehandle[i])); 00614 } 00615 } 00616 00617 if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) { 00618 char *tmp2 = ast_strdupa(tmp); 00619 AST_DECLARE_APP_ARGS(read, 00620 AST_APP_ARG(dsn)[5]; 00621 ); 00622 AST_STANDARD_APP_ARGS(read, tmp2); 00623 for (i = 0; i < 5; i++) { 00624 if (!ast_strlen_zero(read.dsn[i])) 00625 ast_copy_string((*query)->readhandle[i], read.dsn[i], sizeof((*query)->readhandle[i])); 00626 } 00627 } else { 00628 /* If no separate readhandle, then use the writehandle for reading */ 00629 for (i = 0; i < 5; i++) { 00630 if (!ast_strlen_zero((*query)->writehandle[i])) 00631 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i])); 00632 } 00633 } 00634 00635 if ((tmp = ast_variable_retrieve(cfg, catg, "readsql"))) 00636 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00637 else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { 00638 ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); 00639 ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); 00640 } 00641 00642 if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) { 00643 ast_free(*query); 00644 *query = NULL; 00645 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg); 00646 return EINVAL; 00647 } 00648 00649 if ((tmp = ast_variable_retrieve(cfg, catg, "writesql"))) 00650 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00651 else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { 00652 ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); 00653 ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); 00654 } 00655 00656 if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) { 00657 ast_free(*query); 00658 *query = NULL; 00659 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg); 00660 return EINVAL; 00661 } 00662 00663 /* Allow escaping of embedded commas in fields to be turned off */ 00664 ast_set_flag((*query), OPT_ESCAPECOMMAS); 00665 if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) { 00666 if (ast_false(tmp)) 00667 ast_clear_flag((*query), OPT_ESCAPECOMMAS); 00668 } 00669 00670 if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) { 00671 if (strcasecmp(tmp, "multirow") == 0) 00672 ast_set_flag((*query), OPT_MULTIROW); 00673 if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit"))) 00674 sscanf(tmp, "%d", &((*query)->rowlimit)); 00675 } 00676 00677 (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function)); 00678 if (! (*query)->acf) { 00679 ast_free(*query); 00680 *query = NULL; 00681 return ENOMEM; 00682 } 00683 00684 if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { 00685 if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) { 00686 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00687 } 00688 } else { 00689 if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) { 00690 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00691 } 00692 } 00693 00694 if (!((*query)->acf->name)) { 00695 ast_free((*query)->acf); 00696 ast_free(*query); 00697 *query = NULL; 00698 return ENOMEM; 00699 } 00700 00701 if (asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name) < 0) { 00702 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00703 (*query)->acf->syntax = NULL; 00704 } 00705 00706 if (!((*query)->acf->syntax)) { 00707 ast_free((char *)(*query)->acf->name); 00708 ast_free((*query)->acf); 00709 ast_free(*query); 00710 *query = NULL; 00711 return ENOMEM; 00712 } 00713 00714 (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; 00715 00716 res = 0; 00717 if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { 00718 res = asprintf((char **)&((*query)->acf->desc), 00719 "Runs the following query, as defined in func_odbc.conf, performing\n" 00720 "substitution of the arguments into the query as specified by ${ARG1},\n" 00721 "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" 00722 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00723 "\nRead:\n%s\n\nWrite:\n%s\n", 00724 (*query)->sql_read, 00725 (*query)->sql_write); 00726 } else if (!ast_strlen_zero((*query)->sql_read)) { 00727 res = asprintf((char **)&((*query)->acf->desc), 00728 "Runs the following query, as defined in func_odbc.conf, performing\n" 00729 "substitution of the arguments into the query as specified by ${ARG1},\n" 00730 "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", 00731 (*query)->sql_read); 00732 } else if (!ast_strlen_zero((*query)->sql_write)) { 00733 res = asprintf((char **)&((*query)->acf->desc), 00734 "Runs the following query, as defined in func_odbc.conf, performing\n" 00735 "substitution of the arguments into the query as specified by ${ARG1},\n" 00736 "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" 00737 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" 00738 "This function may only be set.\nSQL:\n%s\n", 00739 (*query)->sql_write); 00740 } else { 00741 ast_free((char *)(*query)->acf->syntax); 00742 ast_free((char *)(*query)->acf->name); 00743 ast_free((*query)->acf); 00744 ast_free(*query); 00745 ast_log(LOG_WARNING, "Section %s was found, but there was no SQL to execute. Ignoring.\n", catg); 00746 return EINVAL; 00747 } 00748 00749 if (res < 0) { 00750 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00751 (*query)->acf->desc = NULL; 00752 } 00753 00754 00755 if (!((*query)->acf->desc)) { 00756 ast_free((char *)(*query)->acf->syntax); 00757 ast_free((char *)(*query)->acf->name); 00758 ast_free((*query)->acf); 00759 ast_free(*query); 00760 *query = NULL; 00761 return ENOMEM; 00762 } 00763 00764 if (ast_strlen_zero((*query)->sql_read)) { 00765 (*query)->acf->read = NULL; 00766 } else { 00767 (*query)->acf->read = acf_odbc_read; 00768 } 00769 00770 if (ast_strlen_zero((*query)->sql_write)) { 00771 (*query)->acf->write = NULL; 00772 } else { 00773 (*query)->acf->write = acf_odbc_write; 00774 } 00775 00776 return 0; 00777 }
static int load_module | ( | void | ) | [static] |
Definition at line 796 of file func_odbc.c.
References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), and LOG_NOTICE.
00797 { 00798 int res = 0; 00799 struct ast_config *cfg; 00800 char *catg; 00801 struct ast_flags config_flags = { 0 }; 00802 00803 res |= ast_custom_function_register(&fetch_function); 00804 res |= ast_register_application(app_odbcfinish, exec_odbcfinish, syn_odbcfinish, desc_odbcfinish); 00805 AST_LIST_LOCK(&queries); 00806 00807 cfg = ast_config_load(config, config_flags); 00808 if (!cfg) { 00809 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); 00810 AST_LIST_UNLOCK(&queries); 00811 return AST_MODULE_LOAD_DECLINE; 00812 } 00813 00814 for (catg = ast_category_browse(cfg, NULL); 00815 catg; 00816 catg = ast_category_browse(cfg, catg)) { 00817 struct acf_odbc_query *query = NULL; 00818 int err; 00819 00820 if ((err = init_acf_query(cfg, catg, &query))) { 00821 if (err == ENOMEM) 00822 ast_log(LOG_ERROR, "Out of memory\n"); 00823 else if (err == EINVAL) 00824 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg); 00825 else 00826 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err); 00827 } else { 00828 AST_LIST_INSERT_HEAD(&queries, query, list); 00829 ast_custom_function_register(query->acf); 00830 } 00831 } 00832 00833 ast_config_destroy(cfg); 00834 res |= ast_custom_function_register(&escape_function); 00835 00836 AST_LIST_UNLOCK(&queries); 00837 return res; 00838 }
static void odbc_datastore_free | ( | void * | data | ) | [static] |
Definition at line 88 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.
00089 { 00090 struct odbc_datastore *result = data; 00091 struct odbc_datastore_row *row; 00092 AST_LIST_LOCK(result); 00093 while ((row = AST_LIST_REMOVE_HEAD(result, list))) { 00094 ast_free(row); 00095 } 00096 AST_LIST_UNLOCK(result); 00097 AST_LIST_HEAD_DESTROY(result); 00098 ast_free(result); 00099 }
static int reload | ( | void | ) | [static] |
Definition at line 865 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_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, free_acf_query(), init_acf_query(), and LOG_WARNING.
00866 { 00867 int res = 0; 00868 struct ast_config *cfg; 00869 struct acf_odbc_query *oldquery; 00870 char *catg; 00871 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; 00872 00873 cfg = ast_config_load(config, config_flags); 00874 if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00875 return 0; 00876 00877 AST_LIST_LOCK(&queries); 00878 00879 while (!AST_LIST_EMPTY(&queries)) { 00880 oldquery = AST_LIST_REMOVE_HEAD(&queries, list); 00881 ast_custom_function_unregister(oldquery->acf); 00882 free_acf_query(oldquery); 00883 } 00884 00885 if (!cfg) { 00886 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); 00887 goto reload_out; 00888 } 00889 00890 for (catg = ast_category_browse(cfg, NULL); 00891 catg; 00892 catg = ast_category_browse(cfg, catg)) { 00893 struct acf_odbc_query *query = NULL; 00894 00895 if (init_acf_query(cfg, catg, &query)) { 00896 ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); 00897 } else { 00898 AST_LIST_INSERT_HEAD(&queries, query, list); 00899 ast_custom_function_register(query->acf); 00900 } 00901 } 00902 00903 ast_config_destroy(cfg); 00904 reload_out: 00905 AST_LIST_UNLOCK(&queries); 00906 return res; 00907 }
static int unload_module | ( | void | ) | [static] |
Definition at line 840 of file func_odbc.c.
References acf_odbc_query::acf, ast_custom_function_unregister(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_unregister_application(), escape_function, fetch_function, free_acf_query(), and acf_odbc_query::list.
00841 { 00842 struct acf_odbc_query *query; 00843 int res = 0; 00844 00845 AST_LIST_LOCK(&queries); 00846 while (!AST_LIST_EMPTY(&queries)) { 00847 query = AST_LIST_REMOVE_HEAD(&queries, list); 00848 ast_custom_function_unregister(query->acf); 00849 free_acf_query(query); 00850 } 00851 00852 res |= ast_custom_function_unregister(&escape_function); 00853 res |= ast_custom_function_unregister(&fetch_function); 00854 res |= ast_unregister_application(app_odbcfinish); 00855 00856 /* Allow any threads waiting for this lock to pass (avoids a race) */ 00857 AST_LIST_UNLOCK(&queries); 00858 usleep(1); 00859 AST_LIST_LOCK(&queries); 00860 00861 AST_LIST_UNLOCK(&queries); 00862 return 0; 00863 }
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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 915 of file func_odbc.c.
char* app_odbcfinish = "ODBCFinish" [static] |
Definition at line 574 of file func_odbc.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 915 of file func_odbc.c.
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 576 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 575 of file func_odbc.c.