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