[tracker/unicode-lower] libtracker-data: Use libicu, libunistring or glib for fn:lower-case
- From: Philip Van Hoof <pvanhoof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/unicode-lower] libtracker-data: Use libicu, libunistring or glib for fn:lower-case
- Date: Mon, 28 Mar 2011 11:42:51 +0000 (UTC)
commit b2b7c343f20be014c3554f3db6b36e7bacf1161f
Author: Philip Van Hoof <philip codeminded be>
Date: Mon Mar 28 13:41:47 2011 +0200
libtracker-data: Use libicu, libunistring or glib for fn:lower-case
Fixes NB#240168.
src/libtracker-data/tracker-db-interface-sqlite.c | 142 ++++++++++++++++++++
src/libtracker-data/tracker-sparql-expression.vala | 8 +-
2 files changed, 149 insertions(+), 1 deletions(-)
---
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.c b/src/libtracker-data/tracker-db-interface-sqlite.c
index 298a3c5..92456fa 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.c
+++ b/src/libtracker-data/tracker-db-interface-sqlite.c
@@ -34,6 +34,18 @@
#include <libtracker-fts/tracker-fts.h>
#endif
+#ifdef HAVE_LIBUNISTRING
+/* libunistring versions prior to 9.1.2 need this hack */
+#define _UNUSED_PARAMETER_
+#include <unistr.h>
+#include <unicase.h>
+#elif HAVE_LIBICU
+#include <unicode/utypes.h>
+#include <unicode/uregex.h>
+#include <unicode/ustring.h>
+#include <unicode/ucol.h>
+#endif
+
#include "tracker-collation.h"
#include "tracker-db-interface-sqlite.h"
@@ -521,6 +533,132 @@ function_sparql_regex (sqlite3_context *context,
sqlite3_result_int (context, ret);
}
+#ifdef HAVE_LIBUNISTRING
+
+static void
+function_sparql_lower_case (sqlite3_context *context,
+ int argc,
+ sqlite3_value *argv[])
+{
+ const uint16_t *zInput;
+ uint16_t *zOutput;
+ size_t written = 0;
+ int nInput;
+ int nOutput;
+ const char *zLocale = NULL;
+
+ g_assert (argc == 1 || argc == 2);
+
+ if (argc == 2) {
+ zLocale = (const char *) sqlite3_value_text (argv[1]);
+ }
+
+ zInput = sqlite3_value_text16 (argv[0]);
+
+ if (!zInput) {
+ return;
+ }
+
+ nInput = sqlite3_value_bytes16 (argv[0]);
+
+ nOutput = nInput * 2 + 2;
+ zOutput = sqlite3_malloc (nOutput);
+
+ if (!zOutput) {
+ return;
+ }
+
+ u16_tolower (zInput, nInput, zLocale, NULL, &zOutput, &written);
+
+ sqlite3_result_text16 (context, zOutput, -1, sqlite3_free);
+}
+
+#elif HAVE_LIBICU
+
+static void
+function_sparql_lower_case (sqlite3_context *context,
+ int argc,
+ sqlite3_value *argv[])
+{
+ const UChar *zInput;
+ UChar *zOutput;
+ int nInput;
+ int nOutput;
+ const char *zLocale = 0;
+ UErrorCode status = U_ZERO_ERROR;
+
+ g_assert (argc == 1 || argc == 2);
+
+ if (argc == 2) {
+ zLocale = (const char *) sqlite3_value_text (argv[1]);
+ }
+
+ zInput = sqlite3_value_text16 (argv[0]);
+
+ if (!zInput) {
+ return;
+ }
+
+ nInput = sqlite3_value_bytes16 (argv[0]);
+
+ nOutput = nInput * 2 + 2;
+ zOutput = sqlite3_malloc (nOutput);
+
+ if (!zOutput) {
+ return;
+ }
+
+ u_strToLower (zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
+
+ if (!U_SUCCESS (status)){
+ char zBuf[128];
+ sqlite3_snprintf (128, zBuf, "ICU error: u_strToLower()/u_strToUpper(): %s", u_errorName (status));
+ zBuf[127] = '\0';
+ sqlite3_result_error(context, zBuf, -1);
+ return;
+ }
+
+ sqlite3_result_text16 (context, zOutput, -1, sqlite3_free);
+}
+
+#else /* GLib based */
+
+static void
+function_sparql_lower_case (sqlite3_context *context,
+ int argc,
+ sqlite3_value *argv[])
+{
+ const gchar *zInput;
+ gchar *zOutput;
+ int nInput;
+
+ g_assert (argc == 1 || argc == 2);
+
+ /* GLib API doesn't allow passing of locale (so we ignore argv[1]) */
+ /* GLib API works with UTF-8, so use the UTF-8 functions of SQLite too */
+
+ zInput = (const gchar*) sqlite3_value_text (argv[0]);
+
+ if (!zInput) {
+ return;
+ }
+
+ nInput = sqlite3_value_bytes (argv[0]);
+
+ if (!zOutput) {
+ return;
+ }
+
+ zOutput = g_utf8_strdown (zInput, nInput);
+
+ /* Unfortunately doesn't the GLib API allow us to pass pre-allocated memory,
+ * so we can't use sqlite3_malloc and sqlite3_free here */
+
+ sqlite3_result_text (context, zOutput, -1, g_free);
+}
+
+#endif
+
static inline int
stmt_step (sqlite3_stmt *stmt)
{
@@ -635,6 +773,10 @@ open_database (TrackerDBInterface *db_interface,
db_interface, &function_sparql_uri_is_descendant,
NULL, NULL);
+ sqlite3_create_function (db_interface->db, "SparqlLowerCase", 1, SQLITE_ANY,
+ db_interface, &function_sparql_lower_case,
+ NULL, NULL);
+
sqlite3_extended_result_codes (db_interface->db, 0);
sqlite3_busy_timeout (db_interface->db, 100000);
}
diff --git a/src/libtracker-data/tracker-sparql-expression.vala b/src/libtracker-data/tracker-sparql-expression.vala
index fdb0e2a..04fdcf3 100644
--- a/src/libtracker-data/tracker-sparql-expression.vala
+++ b/src/libtracker-data/tracker-sparql-expression.vala
@@ -411,12 +411,18 @@ class Tracker.Sparql.Expression : Object {
sql.append (" AS REAL)");
return PropertyType.DOUBLE;
- } else if (uri == FN_NS + "lower-case") {
+ } else if (uri == TRACKER_NS + "ascii-lower-case") {
// conversion to string
sql.append ("lower (");
translate_expression_as_string (sql);
sql.append (")");
return PropertyType.STRING;
+ } else if (uri == FN_NS + "lower-case") {
+ // conversion to string
+ sql.append ("SparqlLowerCase (");
+ translate_expression_as_string (sql);
+ sql.append (")");
+ return PropertyType.STRING;
} else if (uri == FN_NS + "contains") {
// fn:contains('A','B') => 'A' GLOB '*B*'
sql.append ("(");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]