diff --git a/configs/samples/func_odbc.conf.sample b/configs/samples/func_odbc.conf.sample index b825974ea780c7c697fd1c8dd8a83d224f819d00..fce8a9261228595829339b41d53b565a97d704e6 100644 --- a/configs/samples/func_odbc.conf.sample +++ b/configs/samples/func_odbc.conf.sample @@ -36,6 +36,10 @@ ; to use the dialplan function SQL_ESC() to escape the data prior to its ; inclusion in the SQL statement. ; +; If you have data which may potentially contain backslashes, you may wish to +; use the dialplan function SQL_ESC_BACKSLASHES() to escape the backslashes. +; Note that not all databases may require escaping of the backslashes. +; ; ; The following options are available in this configuration file: ; diff --git a/doc/CHANGES-staging/func_odbc_esc_backslashes.txt b/doc/CHANGES-staging/func_odbc_esc_backslashes.txt new file mode 100644 index 0000000000000000000000000000000000000000..087bb4214130ea64360598953e4378de428a92fd --- /dev/null +++ b/doc/CHANGES-staging/func_odbc_esc_backslashes.txt @@ -0,0 +1,7 @@ +Subject: func_odbc + +A SQL_ESC_BACKSLASHES dialplan function has been added which +escapes backslashes. Usage of this is dependent on whether the +database in use can use backslashes to escape ticks or not. If +it can, then usage of this prevents a broken SQL query depending +on how the SQL query is constructed. diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 48619b135404f6e0083b30ea9c7bebcaa6545b3e..7e4e6a3bb78706abf448d887d77c8f6cc379ec32 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -96,6 +96,19 @@ <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'</para> </description> </function> + <function name="SQL_ESC_BACKSLASHES" language="en_US"> + <synopsis> + Escapes backslashes for use in SQL statements. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Used in SQL templates to escape data which may contain backslashes + <literal>\</literal> which are otherwise used to escape data.</para> + <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${SQL_ESC_BACKSLASHES(${ARG1})})}'</para> + </description> + </function> ***/ static char *config = "func_odbc.conf"; @@ -1102,13 +1115,13 @@ end_acf_read: return 0; } -static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len, char character) { char *out = buf; for (; *data && out - buf < len; data++) { - if (*data == '\'') { - *out = '\''; + if (*data == character) { + *out = character; out++; } *out++ = *data; @@ -1118,9 +1131,25 @@ static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, cha return 0; } +static int acf_escape_ticks(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + return acf_escape(chan, cmd, data, buf, len, '\''); +} + static struct ast_custom_function escape_function = { .name = "SQL_ESC", - .read = acf_escape, + .read = acf_escape_ticks, + .write = NULL, +}; + +static int acf_escape_backslashes(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + return acf_escape(chan, cmd, data, buf, len, '\\'); +} + +static struct ast_custom_function escape_backslashes_function = { + .name = "SQL_ESC_BACKSLASHES", + .read = acf_escape_backslashes, .write = NULL, }; @@ -1858,6 +1887,7 @@ static int load_module(void) ast_config_destroy(cfg); res |= ast_custom_function_register(&escape_function); + res |= ast_custom_function_register(&escape_backslashes_function); ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc)); AST_RWLIST_UNLOCK(&queries); @@ -1877,6 +1907,7 @@ static int unload_module(void) } res |= ast_custom_function_unregister(&escape_function); + res |= ast_custom_function_unregister(&escape_backslashes_function); res |= ast_custom_function_unregister(&fetch_function); res |= ast_unregister_application(app_odbcfinish); ast_cli_unregister_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));