diff options
Diffstat (limited to 'funcs')
-rw-r--r-- | funcs/func_odbc.c | 194 |
1 files changed, 109 insertions, 85 deletions
diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 1c3a17402..779f68524 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -93,7 +93,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <description> <para>Used in SQL templates to escape data which may contain single ticks <literal>'</literal> which are otherwise used to delimit data.</para> - <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'</para> + <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'</para> </description> </function> ***/ @@ -260,7 +260,10 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co } ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300); - ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300); + /* We only get here if sql_write is set. sql_insert is optional however. */ + if (query->sql_insert) { + ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300); + } /* Parse our arguments */ t = value ? ast_strdupa(value) : ""; @@ -294,7 +297,9 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : ""); ast_str_substitute_variables(&buf, 0, chan, query->sql_write); - ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert); + if (query->sql_insert) { + ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert); + } if (bogus_chan) { chan = ast_channel_unref(chan); @@ -345,44 +350,47 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co if (stmt) { SQLRowCount(stmt, &rows); - } - - if (stmt && rows == 0 && ast_str_strlen(insertbuf) != 0) { SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - if (obj && !transactional) { - ast_odbc_release_obj(obj); - obj = NULL; - } - for (transactional = 0, dsn = 0; dsn < 5; dsn++) { - if (!ast_strlen_zero(query->writehandle[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"); - } else if (obj) { - ast_odbc_release_obj(obj); - obj = NULL; - } + if (rows != 0) { + status = "SUCCESS"; - 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; + } else if (query->sql_insert) { + if (obj && !transactional) { + ast_odbc_release_obj(obj); + obj = NULL; + } + + for (transactional = 0, dsn = 0; dsn < 5; dsn++) { + if (!ast_strlen_zero(query->writehandle[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"); + } else if (obj) { + ast_odbc_release_obj(obj); + obj = NULL; + } + + 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(insertbuf)); + } } - if (obj) { - stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf)); + if (stmt) { + status = "FAILOVER"; + SQLRowCount(stmt, &rows); + SQLCloseCursor(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + break; } } - if (stmt) { - status = "FAILOVER"; - SQLRowCount(stmt, &rows); - break; - } } - } else if (stmt) { - status = "SUCCESS"; } AST_RWLIST_UNLOCK(&queries); @@ -397,10 +405,6 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); } - if (stmt) { - SQLCloseCursor(stmt); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - } if (obj && !transactional) { ast_odbc_release_obj(obj); obj = NULL; @@ -875,15 +879,16 @@ static int free_acf_query(struct acf_odbc_query *query) static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query) { const char *tmp; + const char *tmp2; int i; if (!cfg || !catg) { return EINVAL; } - *query = ast_calloc(1, sizeof(struct acf_odbc_query)); - if (! (*query)) + if (!(*query = ast_calloc(1, sizeof(**query)))) { return ENOMEM; + } if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) { char *tmp2 = ast_strdupa(tmp); @@ -913,30 +918,46 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu if (!ast_strlen_zero((*query)->writehandle[i])) ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i])); } - } + } - if ((tmp = ast_variable_retrieve(cfg, catg, "readsql"))) - (*query)->sql_read = ast_strdup(tmp); - else if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { - ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); - (*query)->sql_read = ast_strdup(tmp); + if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")) || + (tmp2 = ast_variable_retrieve(cfg, catg, "read"))) { + if (!tmp) { + ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); + tmp = tmp2; + } + if (*tmp != '\0') { /* non-empty string */ + if (!((*query)->sql_read = ast_strdup(tmp))) { + free_acf_query(*query); + *query = NULL; + return ENOMEM; + } + } } - if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) { + if ((*query)->sql_read && ast_strlen_zero((*query)->readhandle[0])) { free_acf_query(*query); *query = NULL; ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg); return EINVAL; } - if ((tmp = ast_variable_retrieve(cfg, catg, "writesql"))) - (*query)->sql_write = ast_strdup(tmp); - else if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { - ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); - (*query)->sql_write = ast_strdup(tmp); + if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")) || + (tmp2 = ast_variable_retrieve(cfg, catg, "write"))) { + if (!tmp) { + ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); + tmp = tmp2; + } + if (*tmp != '\0') { /* non-empty string */ + if (!((*query)->sql_write = ast_strdup(tmp))) { + free_acf_query(*query); + *query = NULL; + return ENOMEM; + } + } } - if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) { + if ((*query)->sql_write && ast_strlen_zero((*query)->writehandle[0])) { free_acf_query(*query); *query = NULL; ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg); @@ -944,7 +965,13 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu } if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) { - (*query)->sql_insert = ast_strdup(tmp); + if (*tmp != '\0') { /* non-empty string */ + if (!((*query)->sql_insert = ast_strdup(tmp))) { + free_acf_query(*query); + *query = NULL; + return ENOMEM; + } + } } /* Allow escaping of embedded commas in fields to be turned off */ @@ -962,7 +989,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu } (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function)); - if (! (*query)->acf) { + if (!(*query)->acf) { free_acf_query(*query); *query = NULL; return ENOMEM; @@ -983,7 +1010,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu } } - if (!((*query)->acf->name)) { + if (!(*query)->acf->name) { free_acf_query(*query); *query = NULL; return ENOMEM; @@ -1013,42 +1040,40 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu return ENOMEM; } - if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { + if ((*query)->sql_read && (*query)->sql_write) { ast_string_field_build((*query)->acf, desc, "Runs the following query, as defined in func_odbc.conf, performing\n" - "substitution of the arguments into the query as specified by ${ARG1},\n" + "substitution of the arguments into the query as specified by ${ARG1},\n" "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" "%s" - "\nRead:\n%s\n\nWrite:\n%s\n%s%s%s", - ast_strlen_zero((*query)->sql_insert) ? "" : + "\nRead:\n%s\n\nWrite:\n%s%s%s", + (*query)->sql_insert ? "If the write query affects no rows, the insert query will be\n" - "performed.\n", + "performed.\n" : "", (*query)->sql_read, (*query)->sql_write, - ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n", - ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, - ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); - } else if (!ast_strlen_zero((*query)->sql_read)) { + (*query)->sql_insert ? "\n\nInsert:\n" : "", + (*query)->sql_insert ? (*query)->sql_insert : ""); + } else if ((*query)->sql_read) { ast_string_field_build((*query)->acf, desc, - "Runs the following query, as defined in func_odbc.conf, performing\n" - "substitution of the arguments into the query as specified by ${ARG1},\n" - "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", - (*query)->sql_read); - } else if (!ast_strlen_zero((*query)->sql_write)) { - ast_string_field_build((*query)->acf, desc, "Runs the following query, as defined in func_odbc.conf, performing\n" - "substitution of the arguments into the query as specified by ${ARG1},\n" + "substitution of the arguments into the query as specified by ${ARG1},\n" + "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s", + (*query)->sql_read); + } else if ((*query)->sql_write) { + ast_string_field_build((*query)->acf, desc, + "Runs the following query, as defined in func_odbc.conf, performing\n" + "substitution of the arguments into the query as specified by ${ARG1},\n" "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" - "This function may only be set.\n%sSQL:\n%s\n%s%s%s", - ast_strlen_zero((*query)->sql_insert) ? "" : + "This function may only be set.\n%s\nSQL:\n%s%s%s", + (*query)->sql_insert ? "If the write query affects no rows, the insert query will be\n" - "performed.\n", + "performed.\n" : "", (*query)->sql_write, - ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n", - ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, - ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); + (*query)->sql_insert ? "\n\nInsert:\n" : "", + (*query)->sql_insert ? (*query)->sql_insert : ""); } else { free_acf_query(*query); *query = NULL; @@ -1062,15 +1087,11 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu return ENOMEM; } - if (ast_strlen_zero((*query)->sql_read)) { - (*query)->acf->read = NULL; - } else { + if ((*query)->sql_read) { (*query)->acf->read = acf_odbc_read; } - if (ast_strlen_zero((*query)->sql_write)) { - (*query)->acf->write = NULL; - } else { + if ((*query)->sql_write) { (*query)->acf->write = acf_odbc_write; } @@ -1142,7 +1163,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args return CLI_SHOWUSAGE; } - if (ast_strlen_zero(query->sql_read)) { + if (!query->sql_read) { ast_cli(a->fd, "The function %s has no readsql parameter.\n", a->argv[2]); AST_RWLIST_UNLOCK(&queries); return CLI_SUCCESS; @@ -1355,12 +1376,15 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg return CLI_SHOWUSAGE; } - if (ast_strlen_zero(query->sql_write)) { + if (!query->sql_write) { ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]); AST_RWLIST_UNLOCK(&queries); return CLI_SUCCESS; } + /* FIXME: The code below duplicates code found in acf_odbc_write but + * lacks the newer sql_insert additions. */ + ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300); /* Evaluate function */ |