From fab064deddbf251ffc4a1e692f33bb43b16cf705 Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Tue, 23 Apr 2013 17:36:47 +0900 Subject: [PATCH] EBookBackendSqliteDB: Support regex queries E_BOOK_QUERY_REGEX_NORMAL is supported in summary queries if the query field is summarized, E_BOOK_QUERY_REGEX_RAW and normalized but non-summarized queries are delegated to EBookBackendSexp for matching. --- .../libedata-book/e-book-backend-sqlitedb.c | 92 ++++++++++++++++++++-- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/addressbook/libedata-book/e-book-backend-sqlitedb.c b/addressbook/libedata-book/e-book-backend-sqlitedb.c index 374cd86..8604e6e 100644 --- a/addressbook/libedata-book/e-book-backend-sqlitedb.c +++ b/addressbook/libedata-book/e-book-backend-sqlitedb.c @@ -1266,6 +1266,48 @@ create_collation (gpointer data, } } +static void +ebsdb_regexp (sqlite3_context *context, + int argc, + sqlite3_value **argv) +{ + GRegex *regex; + const gchar *expression; + const gchar *text; + + /* Reuse the same GRegex for all REGEXP queries with the same expression */ + regex = sqlite3_get_auxdata (context, 0); + if (!regex) { + GError *error = NULL; + + expression = (const gchar *)sqlite3_value_text (argv[0]); + + regex = g_regex_new (expression, 0, 0, &error); + + if (!regex) { + sqlite3_result_error (context, + error ? + error->message : + _("Error parsing regular expression"), + -1); + g_clear_error (&error); + return; + } + + /* SQLite will take care of freeing the GRegex when we're done with the query */ + sqlite3_set_auxdata (context, 0, regex, (void(*)(void*))g_regex_unref); + } + + /* Now perform the comparison */ + text = (const gchar *)sqlite3_value_text (argv[1]); + if (text != NULL) { + gboolean match; + + match = g_regex_match (regex, text, 0, NULL); + sqlite3_result_int (context, match ? 1 : 0); + } +} + static gboolean book_backend_sqlitedb_load (EBookBackendSqliteDB *ebsdb, const gchar *filename, @@ -1281,6 +1323,10 @@ book_backend_sqlitedb_load (EBookBackendSqliteDB *ebsdb, if (ret == SQLITE_OK) ret = sqlite3_collation_needed (ebsdb->priv->db, ebsdb, create_collation); + if (ret == SQLITE_OK) + ret = sqlite3_create_function (ebsdb->priv->db, "regexp", 2, SQLITE_UTF8, ebsdb, + ebsdb_regexp, NULL, NULL); + if (ret != SQLITE_OK) { if (!ebsdb->priv->db) { g_set_error ( @@ -2821,6 +2867,23 @@ func_check_phone (struct _ESExp *f, return r; } +static ESExpResult * +func_check_regex_raw (struct _ESExp *f, + gint argc, + struct _ESExpResult **argv, + gpointer data) +{ + /* Raw REGEX queries are not in the summary, we only keep + * normalized data in the summary + */ + ESExpResult *r; + + r = e_sexp_result_new (f, ESEXP_RES_INT); + r->value.number = 0; + + return r; +} + /* 'builtin' functions */ static const struct { const gchar *name; @@ -2838,7 +2901,9 @@ static const struct { { "exists", func_check, 0 }, { "eqphone", func_check_phone, 0 }, { "eqphone_national", func_check_phone, 0 }, - { "eqphone_short", func_check_phone, 0 } + { "eqphone_short", func_check_phone, 0 }, + { "regex_normal", func_check, 0 }, + { "regex_raw", func_check_regex_raw, 0 }, }; static gboolean @@ -3020,7 +3085,8 @@ typedef enum { MATCH_ENDS_WITH, MATCH_PHONE_NUMBER, MATCH_NATIONAL_PHONE_NUMBER, - MATCH_SHORT_PHONE_NUMBER + MATCH_SHORT_PHONE_NUMBER, + MATCH_REGEX } MatchType; typedef enum { @@ -3072,7 +3138,7 @@ convert_string_value (EBookBackendSqliteDB *ebsdb, g_return_val_if_fail (value != NULL, NULL); - if (flags & CONVERT_NORMALIZE) + if ((flags & CONVERT_NORMALIZE) && match != MATCH_REGEX) normal = e_util_utf8_normalize (value); else normal = g_strdup (value); @@ -3096,6 +3162,7 @@ convert_string_value (EBookBackendSqliteDB *ebsdb, case MATCH_IS: case MATCH_PHONE_NUMBER: case MATCH_NATIONAL_PHONE_NUMBER: + case MATCH_REGEX: break; } @@ -3112,7 +3179,7 @@ convert_string_value (EBookBackendSqliteDB *ebsdb, while ((c = *ptr++)) { if (c == '\'') { g_string_append_c (str, '\''); - } else if (c == '%' || c == '^') { + } else if ((c == '%' || c == '^') && match != MATCH_REGEX) { g_string_append_c (str, '^'); escape_modifier_needed = TRUE; } @@ -3131,6 +3198,7 @@ convert_string_value (EBookBackendSqliteDB *ebsdb, case MATCH_PHONE_NUMBER: case MATCH_NATIONAL_PHONE_NUMBER: case MATCH_SHORT_PHONE_NUMBER: + case MATCH_REGEX: break; } @@ -3307,6 +3375,9 @@ field_oper (MatchType match) case MATCH_NATIONAL_PHONE_NUMBER: return "="; + case MATCH_REGEX: + return "REGEXP"; + case MATCH_CONTAINS: case MATCH_BEGINS_WITH: case MATCH_ENDS_WITH: @@ -3501,6 +3572,16 @@ func_eqphone_short (struct _ESExp *f, return convert_match_exp (f, argc, argv, data, MATCH_SHORT_PHONE_NUMBER); } +static ESExpResult * +func_regex (struct _ESExp *f, + gint argc, + struct _ESExpResult **argv, + gpointer data) +{ + return convert_match_exp (f, argc, argv, data, MATCH_REGEX); +} + + /* 'builtin' functions */ static struct { const gchar *name; @@ -3516,7 +3597,8 @@ static struct { { "endswith", func_endswith, 0 }, { "eqphone", func_eqphone, 0 }, { "eqphone_national", func_eqphone_national, 0 }, - { "eqphone_short", func_eqphone_short, 0 } + { "eqphone_short", func_eqphone_short, 0 }, + { "regex_normal", func_regex, 0 } }; static gchar * -- 2.7.4