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