mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-15 06:18:38 +00:00
Merge "realtime: Fix LIKE escaping in SQL backends" into 13
This commit is contained in:
@@ -305,6 +305,11 @@ static char *decode_chunk(char *chunk)
|
|||||||
return orig;
|
return orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
|
||||||
|
|
||||||
|
/* MySQL requires us to escape the escape... yo dawg */
|
||||||
|
static char *ESCAPE_CLAUSE = " ESCAPE '\\\\'";
|
||||||
|
|
||||||
static struct ast_variable *realtime_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
|
static struct ast_variable *realtime_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
|
||||||
{
|
{
|
||||||
struct mysql_conn *dbh;
|
struct mysql_conn *dbh;
|
||||||
@@ -317,6 +322,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
|
|||||||
char *stringp;
|
char *stringp;
|
||||||
char *chunk;
|
char *chunk;
|
||||||
char *op;
|
char *op;
|
||||||
|
char *escape = "";
|
||||||
const struct ast_variable *field = rt_fields;
|
const struct ast_variable *field = rt_fields;
|
||||||
struct ast_variable *var=NULL, *prev=NULL;
|
struct ast_variable *var=NULL, *prev=NULL;
|
||||||
|
|
||||||
@@ -347,20 +353,29 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
|
|||||||
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
||||||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||||
|
|
||||||
if (!strchr(field->name, ' '))
|
if (!strchr(field->name, ' ')) {
|
||||||
op = " =";
|
op = " =";
|
||||||
else
|
} else {
|
||||||
op = "";
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ESCAPE_STRING(buf, field->value);
|
ESCAPE_STRING(buf, field->value);
|
||||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
|
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape);
|
||||||
while ((field = field->next)) {
|
while ((field = field->next)) {
|
||||||
if (!strchr(field->name, ' '))
|
escape = "";
|
||||||
|
if (!strchr(field->name, ' ')) {
|
||||||
op = " =";
|
op = " =";
|
||||||
else
|
} else {
|
||||||
op = "";
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
ESCAPE_STRING(buf, field->value);
|
ESCAPE_STRING(buf, field->value);
|
||||||
ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
|
ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", ast_str_buffer(sql));
|
ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", ast_str_buffer(sql));
|
||||||
@@ -418,6 +433,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
|
|||||||
char *stringp;
|
char *stringp;
|
||||||
char *chunk;
|
char *chunk;
|
||||||
char *op;
|
char *op;
|
||||||
|
char *escape = "";
|
||||||
const struct ast_variable *field = rt_fields;
|
const struct ast_variable *field = rt_fields;
|
||||||
struct ast_variable *var = NULL;
|
struct ast_variable *var = NULL;
|
||||||
struct ast_config *cfg = NULL;
|
struct ast_config *cfg = NULL;
|
||||||
@@ -464,17 +480,29 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
|
|||||||
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
||||||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||||
|
|
||||||
if (!strchr(field->name, ' '))
|
if (!strchr(field->name, ' ')) {
|
||||||
op = " =";
|
op = " =";
|
||||||
else
|
} else {
|
||||||
op = "";
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ESCAPE_STRING(buf, field->value);
|
ESCAPE_STRING(buf, field->value);
|
||||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
|
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape);
|
||||||
while ((field = field->next)) {
|
while ((field = field->next)) {
|
||||||
if (!strchr(field->name, ' ')) op = " ="; else op = "";
|
escape = "";
|
||||||
|
if (!strchr(field->name, ' ')) {
|
||||||
|
op = " =";
|
||||||
|
} else {
|
||||||
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
ESCAPE_STRING(buf, field->value);
|
ESCAPE_STRING(buf, field->value);
|
||||||
ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
|
ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initfield) {
|
if (initfield) {
|
||||||
|
|||||||
@@ -417,6 +417,9 @@ static struct columns *find_column(struct tables *t, const char *colname)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
|
||||||
|
static char *ESCAPE_CLAUSE = " ESCAPE '\\'";
|
||||||
|
|
||||||
static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields)
|
static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields)
|
||||||
{
|
{
|
||||||
RAII_VAR(PGresult *, result, NULL, PQclear);
|
RAII_VAR(PGresult *, result, NULL, PQclear);
|
||||||
@@ -426,6 +429,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
|
|||||||
char *stringp;
|
char *stringp;
|
||||||
char *chunk;
|
char *chunk;
|
||||||
char *op;
|
char *op;
|
||||||
|
char *escape = "";
|
||||||
const struct ast_variable *field = fields;
|
const struct ast_variable *field = fields;
|
||||||
struct ast_variable *var = NULL, *prev = NULL;
|
struct ast_variable *var = NULL, *prev = NULL;
|
||||||
|
|
||||||
@@ -453,7 +457,14 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
|
|||||||
|
|
||||||
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
||||||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||||
op = strchr(field->name, ' ') ? "" : " =";
|
if (!strchr(field->name, ' ')) {
|
||||||
|
op = " =";
|
||||||
|
} else {
|
||||||
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ESCAPE_STRING(escapebuf, field->value);
|
ESCAPE_STRING(escapebuf, field->value);
|
||||||
if (pgresult) {
|
if (pgresult) {
|
||||||
@@ -461,12 +472,17 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, field->name, op, ast_str_buffer(escapebuf));
|
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", tablename, field->name, op, ast_str_buffer(escapebuf), escape);
|
||||||
while ((field = field->next)) {
|
while ((field = field->next)) {
|
||||||
if (!strchr(field->name, ' '))
|
escape = "";
|
||||||
|
if (!strchr(field->name, ' ')) {
|
||||||
op = " =";
|
op = " =";
|
||||||
else
|
} else {
|
||||||
op = "";
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ESCAPE_STRING(escapebuf, field->value);
|
ESCAPE_STRING(escapebuf, field->value);
|
||||||
if (pgresult) {
|
if (pgresult) {
|
||||||
@@ -474,7 +490,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
|
ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We now have our complete statement; Lets connect to the server and execute it. */
|
/* We now have our complete statement; Lets connect to the server and execute it. */
|
||||||
@@ -540,6 +556,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
|
|||||||
char *stringp;
|
char *stringp;
|
||||||
char *chunk;
|
char *chunk;
|
||||||
char *op;
|
char *op;
|
||||||
|
char *escape = "";
|
||||||
struct ast_variable *var = NULL;
|
struct ast_variable *var = NULL;
|
||||||
struct ast_config *cfg = NULL;
|
struct ast_config *cfg = NULL;
|
||||||
struct ast_category *cat = NULL;
|
struct ast_category *cat = NULL;
|
||||||
@@ -578,10 +595,15 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
|
|||||||
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
||||||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||||
|
|
||||||
if (!strchr(field->name, ' '))
|
if (!strchr(field->name, ' ')) {
|
||||||
op = " =";
|
op = " =";
|
||||||
else
|
escape = "";
|
||||||
|
} else {
|
||||||
op = "";
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ESCAPE_STRING(escapebuf, field->value);
|
ESCAPE_STRING(escapebuf, field->value);
|
||||||
if (pgresult) {
|
if (pgresult) {
|
||||||
@@ -590,12 +612,18 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(escapebuf));
|
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(escapebuf), escape);
|
||||||
while ((field = field->next)) {
|
while ((field = field->next)) {
|
||||||
if (!strchr(field->name, ' '))
|
escape = "";
|
||||||
|
if (!strchr(field->name, ' ')) {
|
||||||
op = " =";
|
op = " =";
|
||||||
else
|
escape = "";
|
||||||
|
} else {
|
||||||
op = "";
|
op = "";
|
||||||
|
if (IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
escape = ESCAPE_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ESCAPE_STRING(escapebuf, field->value);
|
ESCAPE_STRING(escapebuf, field->value);
|
||||||
if (pgresult) {
|
if (pgresult) {
|
||||||
@@ -604,7 +632,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
|
ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initfield) {
|
if (initfield) {
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
/*** DOCUMENTATION
|
/*** DOCUMENTATION
|
||||||
***/
|
***/
|
||||||
|
|
||||||
|
static int has_explicit_like_escaping;
|
||||||
|
|
||||||
static struct ast_config *realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked);
|
static struct ast_config *realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked);
|
||||||
static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields);
|
static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields);
|
||||||
static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields);
|
static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields);
|
||||||
@@ -779,6 +781,8 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
|
||||||
|
|
||||||
/*! \brief Helper function for single and multi-row realtime load functions */
|
/*! \brief Helper function for single and multi-row realtime load functions */
|
||||||
static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
|
static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
|
||||||
{
|
{
|
||||||
@@ -804,6 +808,15 @@ static int realtime_sqlite3_helper(const char *database, const char *table, cons
|
|||||||
ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name),
|
ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name),
|
||||||
sqlite3_escape_value(field->value));
|
sqlite3_escape_value(field->value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_explicit_like_escaping && IS_SQL_LIKE_CLAUSE(field->name)) {
|
||||||
|
/*
|
||||||
|
* The realtime framework is going to pre-escape these
|
||||||
|
* for us with a backslash. We just need to make sure
|
||||||
|
* to tell SQLite about it
|
||||||
|
*/
|
||||||
|
ast_str_append(&sql, 0, " ESCAPE '\\'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_multi) {
|
if (!is_multi) {
|
||||||
@@ -1309,6 +1322,29 @@ static int unload_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void discover_sqlite3_caps(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* So we cheat a little bit here. SQLite3 added support for the
|
||||||
|
* 'ESCAPE' keyword in 3.1.0. They added SQLITE_VERSION_NUMBER
|
||||||
|
* in 3.1.2. So if we run into 3.1.0 or 3.1.1 in the wild, we
|
||||||
|
* just treat it like < 3.1.0.
|
||||||
|
*
|
||||||
|
* For reference: 3.1.0, 3.1.1, and 3.1.2 were all released
|
||||||
|
* within 30 days of each other in Jan/Feb 2005, so I don't
|
||||||
|
* imagine we'll be finding something pre-3.1.2 that often in
|
||||||
|
* practice.
|
||||||
|
*/
|
||||||
|
#if defined(SQLITE_VERSION_NUMBER)
|
||||||
|
has_explicit_like_escaping = 1;
|
||||||
|
#else
|
||||||
|
has_explicit_like_escaping = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ast_debug(3, "SQLite3 has 'LIKE ... ESCAPE ...' support? %s\n",
|
||||||
|
has_explicit_like_escaping ? "Yes" : "No");
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Load the module
|
* \brief Load the module
|
||||||
*
|
*
|
||||||
@@ -1321,6 +1357,8 @@ static int unload_module(void)
|
|||||||
*/
|
*/
|
||||||
static int load_module(void)
|
static int load_module(void)
|
||||||
{
|
{
|
||||||
|
discover_sqlite3_caps();
|
||||||
|
|
||||||
if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) {
|
if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) {
|
||||||
return AST_MODULE_LOAD_FAILURE;
|
return AST_MODULE_LOAD_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user