Merge "realtime: Fix LIKE escaping in SQL backends"

changes/47/5047/1
zuul 9 years ago committed by Gerrit Code Review
commit 144b09ab41

@ -303,6 +303,11 @@ static char *decode_chunk(char *chunk)
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)
{
struct mysql_conn *dbh;
@ -315,6 +320,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
char *stringp;
char *chunk;
char *op;
char *escape = "";
const struct ast_variable *field = rt_fields;
struct ast_variable *var=NULL, *prev=NULL;
@ -345,20 +351,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
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
if (!strchr(field->name, ' '))
op = " =";
else
if (!strchr(field->name, ' ')) {
op = " =";
} else {
op = "";
if (IS_SQL_LIKE_CLAUSE(field->name)) {
escape = ESCAPE_CLAUSE;
}
}
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)) {
if (!strchr(field->name, ' '))
op = " =";
else
escape = "";
if (!strchr(field->name, ' ')) {
op = " =";
} else {
op = "";
if (IS_SQL_LIKE_CLAUSE(field->name)) {
escape = ESCAPE_CLAUSE;
}
}
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));
@ -416,6 +431,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
char *stringp;
char *chunk;
char *op;
char *escape = "";
const struct ast_variable *field = rt_fields;
struct ast_variable *var = NULL;
struct ast_config *cfg = NULL;
@ -462,17 +478,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
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 = " =";
else
} else {
op = "";
if (IS_SQL_LIKE_CLAUSE(field->name)) {
escape = ESCAPE_CLAUSE;
}
}
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)) {
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);
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) {

@ -382,6 +382,9 @@ static struct columns *find_column(struct tables *t, const char *colname)
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)
{
RAII_VAR(PGresult *, result, NULL, PQclear);
@ -391,6 +394,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
char *stringp;
char *chunk;
char *op;
char *escape = "";
const struct ast_variable *field = fields;
struct ast_variable *var = NULL, *prev = NULL;
@ -418,7 +422,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
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);
if (pgresult) {
@ -426,12 +437,17 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
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)) {
if (!strchr(field->name, ' '))
escape = "";
if (!strchr(field->name, ' ')) {
op = " =";
else
} else {
op = "";
if (IS_SQL_LIKE_CLAUSE(field->name)) {
escape = ESCAPE_CLAUSE;
}
}
ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
@ -439,7 +455,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
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. */
@ -505,6 +521,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
char *stringp;
char *chunk;
char *op;
char *escape = "";
struct ast_variable *var = NULL;
struct ast_config *cfg = NULL;
struct ast_category *cat = NULL;
@ -543,10 +560,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
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 = " =";
else
escape = "";
} else {
op = "";
if (IS_SQL_LIKE_CLAUSE(field->name)) {
escape = ESCAPE_CLAUSE;
}
}
ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
@ -555,12 +577,18 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
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)) {
if (!strchr(field->name, ' '))
escape = "";
if (!strchr(field->name, ' ')) {
op = " =";
else
escape = "";
} else {
op = "";
if (IS_SQL_LIKE_CLAUSE(field->name)) {
escape = ESCAPE_CLAUSE;
}
}
ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
@ -569,7 +597,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
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) {

@ -58,6 +58,8 @@
/*** 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_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);
@ -777,6 +779,8 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char
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 */
static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
{
@ -802,6 +806,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),
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) {
@ -1307,6 +1320,29 @@ static int unload_module(void)
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
*
@ -1319,6 +1355,8 @@ static int unload_module(void)
*/
static int load_module(void)
{
discover_sqlite3_caps();
if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) {
return AST_MODULE_LOAD_FAILURE;
}

Loading…
Cancel
Save