From 758f99be49eac82af5634ab2080c9c8ea2295564 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Sat, 20 Mar 2010 23:41:59 +0000 Subject: [PATCH] Support unicode-aware comparisons in Sqlite3. Fixes issue #71 --- CMakeLists.txt | 2 ++ src/CMakeLists.txt | 1 + src/librarybackend.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b0bc1a10..2959d4812 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,8 @@ endif(WIN32) find_package(OpenGL REQUIRED) find_package(Boost REQUIRED) +find_library(SQLITE3_LIBRARIES sqlite3) + if(WIN32) find_library(TAGLIB_LIBRARIES tag) else(WIN32) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 36ac028b5..1bd2d8e85 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -208,6 +208,7 @@ target_link_libraries(clementine_lib ${LIBNOTIFY_LIBRARIES} ${TAGLIB_LIBRARIES} ${QT_LIBRARIES} + ${SQLITE3_LIBRARIES} ) if (APPLE) target_link_libraries(clementine_lib diff --git a/src/librarybackend.cpp b/src/librarybackend.cpp index 0d9b89aca..b96e9f2f7 100644 --- a/src/librarybackend.cpp +++ b/src/librarybackend.cpp @@ -7,13 +7,37 @@ #include #include #include +#include #include #include #include +#include + const char* LibraryBackend::kDatabaseName = "clementine.db"; const int LibraryBackend::kSchemaVersion = 3; +// Custom LIKE(X, Y) function for sqlite3 that supports case insensitive unicode matching. +void SqliteLike(sqlite3_context* context, int argc, sqlite3_value** argv) { + Q_ASSERT(argc == 2 || argc == 3); + Q_ASSERT(sqlite3_value_type(argv[0]) == sqlite3_value_type(argv[1])); + switch (sqlite3_value_type(argv[0])) { + case SQLITE_INTEGER: { + qint64 result = sqlite3_value_int64(argv[0]) - sqlite3_value_int64(argv[1]); + sqlite3_result_int64(context, result ? 0 : 1); + break; + } + case SQLITE_TEXT: { + const uchar* data_a = sqlite3_value_text(argv[0]); + const uchar* data_b = sqlite3_value_text(argv[1]); + QString a = QString::fromUtf8(reinterpret_cast(data_a)).section('%', 1, 1); + QString b = QString::fromUtf8(reinterpret_cast(data_b)); + sqlite3_result_int64(context, b.contains(a, Qt::CaseInsensitive) ? 1 : 0); + break; + } + } +} + LibraryBackend::LibraryBackend(QObject* parent, const QString& database_name) : QObject(parent), injected_database_name_(database_name) @@ -60,6 +84,21 @@ QSqlDatabase LibraryBackend::Connect() { emit Error("LibraryBackend: " + db.lastError().text()); return db; } + // We want Unicode aware LIKE clauses. + QVariant v = db.driver()->handle(); + if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0) { + sqlite3* handle = *static_cast(v.data()); + if (handle) { + sqlite3_create_function( + handle, // Sqlite3 handle. + "LIKE", // Function name (either override or new). + 2, // Number of args. + SQLITE_ANY, // What types this function accepts. + NULL, // Custom data available via sqlite3_user_data(). + &SqliteLike, // Our function :-) + NULL, NULL); + } + } if (db.tables().count() == 0) { // Set up initial schema