From 29eb4fe6203c75dd903d5128da47a51473a93297 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 12 Jul 2023 12:03:59 -0400 Subject: [PATCH] extconfig: Allow explicit DB result set ordering to be disabled. Added a new boolean configuration flag - `order_multi_row_results_by_initial_column` - to both res_pgsql.conf and res_config_odbc.conf that allows the administrator to disable the explicit `ORDER BY` that was previously being added to all generated SQL statements that returned multiple rows. Fixes: #179 --- configs/samples/res_config_odbc.conf.sample | 14 +++++++ configs/samples/res_pgsql.conf.sample | 6 +++ res/res_config_odbc.c | 44 +++++++++++++++++---- res/res_config_pgsql.c | 7 +++- 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 configs/samples/res_config_odbc.conf.sample diff --git a/configs/samples/res_config_odbc.conf.sample b/configs/samples/res_config_odbc.conf.sample new file mode 100644 index 0000000000..1e4767cde6 --- /dev/null +++ b/configs/samples/res_config_odbc.conf.sample @@ -0,0 +1,14 @@ +; +; Sample configuration for res_config_odbc +; +; Most configuration occurs in the system ODBC configuration files, +; res_odbc.conf, and extconfig.conf. You only need this file in the +; event that you want to influence default sorting behavior. +; + +[general] +; When multiple rows are requested by realtime, res_config_odbc will add an +; explicit ORDER BY clause to the generated SELECT statement. To prevent +; that from occuring, set order_multi_row_results_by_initial_column to 'no'. +; +;order_multi_row_results_by_initial_column=no diff --git a/configs/samples/res_pgsql.conf.sample b/configs/samples/res_pgsql.conf.sample index 015d68c13c..717821c8e1 100644 --- a/configs/samples/res_pgsql.conf.sample +++ b/configs/samples/res_pgsql.conf.sample @@ -28,3 +28,9 @@ dbpass=password ; createchar - Create char columns only ; requirements=warn + +; When multiple rows are requested by realtime, res_config_pgsql will add an +; explicit ORDER BY clause to the generated SELECT statement. To prevent +; that from occuring, set order_multi_row_results_by_initial_column to 'no'. +; +;order_multi_row_results_by_initial_column=no diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index b6a878a853..cecbd1792f 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -49,6 +49,9 @@ /*! Initial SQL query buffer size to allocate. */ #define SQL_BUF_SIZE 1024 +static const char *res_config_odbc_conf = "res_config_odbc.conf"; +static int order_multi_row_results_by_initial_column = 1; + AST_THREADSTORAGE(sql_buf); AST_THREADSTORAGE(rowdata_buf); @@ -388,7 +391,10 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op, strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : ""); } - ast_str_append(&sql, 0, " ORDER BY %s", initfield); + + if (order_multi_row_results_by_initial_column) { + ast_str_append(&sql, 0, " ORDER BY %s", initfield); + } cps.sql = ast_str_buffer(sql); @@ -954,7 +960,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c memset(&q, 0, sizeof(q)); - if (!file || !strcmp (file, "res_config_odbc.conf") || !sql) { + if (!file || !strcmp (file, res_config_odbc_conf) || !sql) { return NULL; /* cant configure myself with myself ! */ } @@ -1248,22 +1254,46 @@ static struct ast_config_engine odbc_engine = { .unload_func = unload_odbc, }; -static int unload_module (void) +static void load_config(const char *filename) { - ast_config_engine_deregister(&odbc_engine); + struct ast_config *config; + struct ast_flags config_flags = { 0 }; + const char *s; - return 0; + config = ast_config_load(filename, config_flags); + if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) { + if (config == CONFIG_STATUS_FILEINVALID) { + ast_log(LOG_WARNING, "Unable to load config '%s'. Using defaults.\n", filename); + } + order_multi_row_results_by_initial_column = 1; + return; + } + + /* Result set ordering is enabled by default */ + s = ast_variable_retrieve(config, "general", "order_multi_row_results_by_initial_column"); + order_multi_row_results_by_initial_column = !s || ast_true(s); + + ast_config_destroy(config); } -static int load_module (void) +static int load_module(void) { + /* We'll either successfully load the configuration or fail with reasonable + * defaults */ + load_config(res_config_odbc_conf); ast_config_engine_register(&odbc_engine); - return 0; } static int reload_module(void) { + load_config(res_config_odbc_conf); + return 0; +} + +static int unload_module(void) +{ + ast_config_engine_deregister(&odbc_engine); return 0; } diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 62a3565e02..2bdffea2c3 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -82,6 +82,7 @@ static char dbappname[MAX_DB_OPTION_SIZE] = ""; static char dbsock[MAX_DB_OPTION_SIZE] = ""; static int dbport = 5432; static time_t connect_time = 0; +static int order_multi_row_results_by_initial_column = 1; static int parse_config(int reload); static int pgsql_reconnect(const char *database); @@ -624,7 +625,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape); } - if (initfield) { + if (initfield && order_multi_row_results_by_initial_column) { ast_str_append(&sql, 0, " ORDER BY %s", initfield); } @@ -1524,6 +1525,10 @@ static int parse_config(int is_reload) requirements = RQ_CREATECHAR; } + /* Result set ordering is enabled by default */ + s = ast_variable_retrieve(config, "general", "order_multi_row_results_by_initial_column"); + order_multi_row_results_by_initial_column = !s || ast_true(s); + ast_config_destroy(config); if (DEBUG_ATLEAST(1)) {