|
|
|
@ -233,17 +233,23 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|
|
|
|
if (!query) {
|
|
|
|
|
ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
|
|
|
|
|
AST_RWLIST_UNLOCK(&queries);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
if (chan) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!chan) {
|
|
|
|
|
if ((chan = ast_channel_alloc(0, AST_STATE_DOWN, "", "", "", "", "", "", 0, "Bogus/func_odbc")))
|
|
|
|
|
bogus_chan = 1;
|
|
|
|
|
if (!(chan = ast_dummy_channel_alloc())) {
|
|
|
|
|
AST_RWLIST_UNLOCK(&queries);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
bogus_chan = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chan)
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
ast_autoservice_start(chan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
|
|
|
|
|
ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
|
|
|
|
@ -254,12 +260,11 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|
|
|
|
if (!s || !t) {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory\n");
|
|
|
|
|
AST_RWLIST_UNLOCK(&queries);
|
|
|
|
|
if (chan)
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
if (bogus_chan) {
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
} else {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
} else {
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
@ -283,44 +288,48 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|
|
|
|
ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
|
|
|
|
|
ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
|
|
|
|
|
|
|
|
|
|
/* Restore prior values */
|
|
|
|
|
for (i = 0; i < args.argc; i++) {
|
|
|
|
|
snprintf(varname, sizeof(varname), "ARG%d", i + 1);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, varname, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < values.argc; i++) {
|
|
|
|
|
snprintf(varname, sizeof(varname), "VAL%d", i + 1);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, varname, NULL);
|
|
|
|
|
}
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "VALUE", NULL);
|
|
|
|
|
|
|
|
|
|
/*!\note
|
|
|
|
|
* Okay, this part is confusing. Transactions belong to a single database
|
|
|
|
|
* handle. Therefore, when working with transactions, we CANNOT failover
|
|
|
|
|
* to multiple DSNs. We MUST have a single handle all the way through the
|
|
|
|
|
* transaction, or else we CANNOT enforce atomicity.
|
|
|
|
|
*/
|
|
|
|
|
for (dsn = 0; dsn < 5; dsn++) {
|
|
|
|
|
if (transactional) {
|
|
|
|
|
/* This can only happen second time through or greater. */
|
|
|
|
|
ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
|
|
|
|
|
if (bogus_chan) {
|
|
|
|
|
chan = ast_channel_release(chan);
|
|
|
|
|
} else {
|
|
|
|
|
/* Restore prior values */
|
|
|
|
|
for (i = 0; i < args.argc; i++) {
|
|
|
|
|
snprintf(varname, sizeof(varname), "ARG%d", i + 1);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, varname, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(query->writehandle[dsn])) {
|
|
|
|
|
if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
|
|
|
|
|
transactional = 1;
|
|
|
|
|
} else {
|
|
|
|
|
obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
|
|
|
|
|
transactional = 0;
|
|
|
|
|
for (i = 0; i < values.argc; i++) {
|
|
|
|
|
snprintf(varname, sizeof(varname), "VAL%d", i + 1);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, varname, NULL);
|
|
|
|
|
}
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "VALUE", NULL);
|
|
|
|
|
|
|
|
|
|
/*!\note
|
|
|
|
|
* Okay, this part is confusing. Transactions belong to a single database
|
|
|
|
|
* handle. Therefore, when working with transactions, we CANNOT failover
|
|
|
|
|
* to multiple DSNs. We MUST have a single handle all the way through the
|
|
|
|
|
* transaction, or else we CANNOT enforce atomicity.
|
|
|
|
|
*/
|
|
|
|
|
for (dsn = 0; dsn < 5; dsn++) {
|
|
|
|
|
if (transactional) {
|
|
|
|
|
/* This can only happen second time through or greater. */
|
|
|
|
|
ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
|
|
|
|
|
}
|
|
|
|
|
if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(query->writehandle[dsn])) {
|
|
|
|
|
if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
|
|
|
|
|
transactional = 1;
|
|
|
|
|
} else {
|
|
|
|
|
obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
|
|
|
|
|
transactional = 0;
|
|
|
|
|
}
|
|
|
|
|
if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (obj && !transactional) {
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
if (obj && !transactional) {
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -351,9 +360,11 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|
|
|
|
* flag this as -1 rows. Note that this is different from 0 affected rows
|
|
|
|
|
* which would be the case if we succeeded in our query, but the values did
|
|
|
|
|
* not change. */
|
|
|
|
|
snprintf(varname, sizeof(varname), "%d", (int)rows);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
snprintf(varname, sizeof(varname), "%d", (int)rows);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stmt) {
|
|
|
|
|
SQLCloseCursor(stmt);
|
|
|
|
@ -364,10 +375,9 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|
|
|
|
obj = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chan)
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
if (bogus_chan)
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -392,7 +402,9 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
const char *status = "FAILURE";
|
|
|
|
|
|
|
|
|
|
if (!sql) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
if (chan) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -408,18 +420,22 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
if (!query) {
|
|
|
|
|
ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
|
|
|
|
|
AST_RWLIST_UNLOCK(&queries);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
if (chan) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!chan) {
|
|
|
|
|
if ((chan = ast_channel_alloc(0, AST_STATE_DOWN, "", "", "", "", "", "", 0, "Bogus/func_odbc"))) {
|
|
|
|
|
bogus_chan = 1;
|
|
|
|
|
if (!(chan = ast_dummy_channel_alloc())) {
|
|
|
|
|
AST_RWLIST_UNLOCK(&queries);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
bogus_chan = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chan) {
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
ast_autoservice_start(chan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -431,15 +447,19 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
|
|
|
|
|
ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
|
|
|
|
|
|
|
|
|
|
/* Restore prior values */
|
|
|
|
|
for (x = 0; x < args.argc; x++) {
|
|
|
|
|
snprintf(varname, sizeof(varname), "ARG%d", x + 1);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, varname, NULL);
|
|
|
|
|
if (bogus_chan) {
|
|
|
|
|
chan = ast_channel_release(chan);
|
|
|
|
|
} else {
|
|
|
|
|
/* Restore prior values */
|
|
|
|
|
for (x = 0; x < args.argc; x++) {
|
|
|
|
|
snprintf(varname, sizeof(varname), "ARG%d", x + 1);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, varname, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Save these flags, so we can release the lock */
|
|
|
|
|
escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
|
|
|
|
|
if (ast_test_flag(query, OPT_MULTIROW)) {
|
|
|
|
|
if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
|
|
|
|
|
resultset = ast_calloc(1, sizeof(*resultset));
|
|
|
|
|
AST_LIST_HEAD_INIT(resultset);
|
|
|
|
|
if (query->rowlimit) {
|
|
|
|
@ -468,13 +488,10 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
obj = NULL;
|
|
|
|
|
}
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
if (chan) {
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
}
|
|
|
|
|
if (bogus_chan) {
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -485,13 +502,10 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
obj = NULL;
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
if (chan) {
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
}
|
|
|
|
|
if (bogus_chan) {
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -512,12 +526,11 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
obj = NULL;
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
if (chan)
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
if (bogus_chan)
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
}
|
|
|
|
|
return res1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -558,10 +571,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
obj = NULL;
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
|
|
|
|
|
if (chan)
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
if (bogus_chan)
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
resultset = tmp;
|
|
|
|
@ -636,41 +646,39 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_acf_read:
|
|
|
|
|
snprintf(rowcount, sizeof(rowcount), "%d", y);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
|
|
|
|
|
if (resultset) {
|
|
|
|
|
int uid;
|
|
|
|
|
struct ast_datastore *odbc_store;
|
|
|
|
|
uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
|
|
|
|
|
snprintf(buf, len, "%d", uid);
|
|
|
|
|
odbc_store = ast_datastore_alloc(&odbc_info, buf);
|
|
|
|
|
if (!odbc_store) {
|
|
|
|
|
ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
|
|
|
|
|
odbc_datastore_free(resultset);
|
|
|
|
|
SQLCloseCursor(stmt);
|
|
|
|
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
obj = NULL;
|
|
|
|
|
if (chan)
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
snprintf(rowcount, sizeof(rowcount), "%d", y);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
|
|
|
|
|
if (resultset) {
|
|
|
|
|
int uid;
|
|
|
|
|
struct ast_datastore *odbc_store;
|
|
|
|
|
uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
|
|
|
|
|
snprintf(buf, len, "%d", uid);
|
|
|
|
|
odbc_store = ast_datastore_alloc(&odbc_info, buf);
|
|
|
|
|
if (!odbc_store) {
|
|
|
|
|
ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
|
|
|
|
|
odbc_datastore_free(resultset);
|
|
|
|
|
SQLCloseCursor(stmt);
|
|
|
|
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
obj = NULL;
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
if (bogus_chan)
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
return -1;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
odbc_store->data = resultset;
|
|
|
|
|
ast_channel_datastore_add(chan, odbc_store);
|
|
|
|
|
}
|
|
|
|
|
odbc_store->data = resultset;
|
|
|
|
|
ast_channel_datastore_add(chan, odbc_store);
|
|
|
|
|
}
|
|
|
|
|
SQLCloseCursor(stmt);
|
|
|
|
|
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
|
|
|
|
ast_odbc_release_obj(obj);
|
|
|
|
|
obj = NULL;
|
|
|
|
|
if (chan)
|
|
|
|
|
if (!bogus_chan) {
|
|
|
|
|
ast_autoservice_stop(chan);
|
|
|
|
|
if (bogus_chan)
|
|
|
|
|
ast_channel_release(chan);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|