Russian Qt Forum
Ноябрь 23, 2024, 15:08 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [SOLVED] SQLITE регистронезависимый LIKE  (Прочитано 29040 раз)
Termit
Самовар
**
Offline Offline

Сообщений: 144



Просмотр профиля WWW
« : Сентябрь 24, 2010, 14:31 »

День добрый!

Господа подскажите следующий вопрос.

Есть:
Linux (Kubuntu. Кодировка UTF-8)
QT 4.6
База SQLITE
Приложение работающее с этой базой

Нужно:
Заставить базу работать с регистронезависимым LIKE для русских букв.

Всю голову сломал и почти весь гугле перелопатил, никак не найду ответа.

Читал за ICU, скомпилил библиотеку через command line интерфейс с этой базой через ".load 'libSqliteIcu.so';" и "SELECT icu_load_collation('ru_RU', 'RUSSIAN')" все работает как нужно.
Если это же пишу в приложении ничего не получаеться

Код:
QSqlQuery query(db);
qDebug() << "load extension res = " << query.exec(".load 'libSqliteIcu.so'; ");
qDebug() << "error = " << query.lastError().text();
qDebug() << "load collation res = " << query.exec("SELECT icu_load_collation('ru_RU', 'RUSSIAN')");
qDebug() << "error = " << query.lastError().text();

load extension res =  false
error =  "near ".": syntax error Unable to execute statement"
load collation res =  false
error =  "no such function: icu_load_collation Unable to execute statement"

Проскакивала информация что можно как-то через "QVariant QSqlDriver::handle () const   [virtual]"
В Assistant-е написано
Код:
QSqlDatabase db = ...;
 QVariant v = db.driver()->handle();
 if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*")==0) {
     // v.data() returns a pointer to the handle
     sqlite3 *handle = *static_cast<sqlite3 **>(v.data());
     if (handle != 0) { // check that it is not NULL
         ...
     }
 }
В доке по SQLITE
Цитировать
Instead of providing full Unicode case support by default, SQLite provides the ability to link against external Unicode comparison and conversion routines. The application can overload the built-in NOCASE collating sequence (using sqlite3_create_collation()) and the built-in like(), upper(), and lower() functions (using sqlite3_create_function()). The SQLite source code includes an "ICU" extension that does these overloads. Or, developers can write their own overloads based on their own Unicode-aware comparison routines already contained within their project.

Но, что-то не могу осилить... :-(

Собственно сам вопрос. Как заставить SQLITE понимать регистронезависимый поиск в базе по русским словам?
« Последнее редактирование: Сентябрь 25, 2010, 16:01 от Termit » Записан

Человеческая глупость дает представление о бесконечности
(с) Иоанна Хмелевская
Termit
Самовар
**
Offline Offline

Сообщений: 144



Просмотр профиля WWW
« Ответ #1 : Сентябрь 24, 2010, 16:40 »

Собственно в FAQ, который был процитирован, четко сказано, что данная ф-ция работает только для ASCII. Для прочих кодировок нужно писать свои функции like(), upper(), lower() и пр. Или как вариант собрать SQLITE с ICU.

Та не вопрос, напишу свои функции для чего угодно :-) Это ясно...
Вопрос как прикрутить эти самые функции?

По примеру и Assistant получу я handler sqlite. И чего с ним делать? Как добавить туда эти самые функции?
Записан

Человеческая глупость дает представление о бесконечности
(с) Иоанна Хмелевская
DmP
Гость
« Ответ #2 : Сентябрь 24, 2010, 16:48 »

Собственно в FAQ, который был процитирован, четко сказано, что данная ф-ция работает только для ASCII. Для прочих кодировок нужно писать свои функции like(), upper(), lower() и пр. Или как вариант собрать SQLITE с ICU.

Та не вопрос, напишу свои функции для чего угодно :-) Это ясно...
Вопрос как прикрутить эти самые функции?

По примеру и Assistant получу я handler sqlite. И чего с ним делать? Как добавить туда эти самые функции?
В документации все есть:
http://www.sqlite.org/c3ref/create_collation.html
http://www.sqlite.org/c3ref/create_function.html

Вот не заметил, что уже собрано с ICU. ".load" - это команда шела, а не SQL.
Если посмотреть в исходники шела, то увидим обработку этой команды:
Код:
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
    const char *zFile, *zProc;
    char *zErrMsg = 0;
    zFile = azArg[1];
    zProc = nArg>=3 ? azArg[2] : 0;
    open_db(p);
    rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
    if( rc!=SQLITE_OK ){
      fprintf(stderr, "Error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
      rc = 1;
    }
  }
Попробуйте сделать так же.
Записан
DmP
Гость
« Ответ #3 : Сентябрь 24, 2010, 17:05 »

Вот только вопрос как вызвать эту sqlite3_load_extension.
Как вариант можно пропатчит QSQLiteDriver, например, добавив в него функцию loadExtension() вызывающую sqlite3_load_extension(). Пересобрать плагин.
Потом все просто:
Цитировать
QSQLiteDriver* driver = qobject_cast<QSQLiteDriver*>(mydb.driver());
driver->loadExtension("libSqliteIcu.so");
« Последнее редактирование: Сентябрь 24, 2010, 17:09 от DmP » Записан
Termit
Самовар
**
Offline Offline

Сообщений: 144



Просмотр профиля WWW
« Ответ #4 : Сентябрь 25, 2010, 16:01 »

Решение найдено.

Итого:

1. Необходимо установить пакеты
 
Код:
- libsqlite3-dev
- sqlite3-0-dbg (необязательно)

2. Скачиваем icu.c
 
Код:
wget www.sqlite.org/cvstrac/getfile?f=sqlite/ext/icu/icu.c -O icu.c

3. Собираем
Код:
gcc -shared icu.c `icu-config --ldflags` -o libSqliteIcu.so
для AMD 64
Код:
gcc -shared icu.c `icu-config --ldflags` -fPIC -o libSqliteIcu.so
копируем полученную библиотеку (libSqliteIcu.so) в нужное нам место (я скопировал в /usr/lib)

4. В pro файл проекта добавляем
Код:
...
LIBS += -lsqlite3
...


5. В проект добавляем
Код:
...
#include <sqlite3ext.h>
...
/*
После того как базу данных открыли пишем
*/
QVariant v = db.driver()->handle();
if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*")==0) {
  sqlite3 *handle = *static_cast<sqlite3 **>(v.data());
  if (handle != 0) { // check that it is not NULL
    int res = sqlite3_enable_load_extension(handle,1);
    if (res == SQLITE_OK)
    {
      res = sqlite3_load_extension(handle,"libSqliteIcu.so",0,0);
      if (res == SQLITE_OK)
        qDebug() << "Sqlite3 load ICU extension sucessfully";
      else
        qDebug() <<  "Sqlite3 load ICU extension fail";
    }
  else
    qDebug() << "Sqlite3 enable load extension fail";
    }
}
...

Получаем подключение к sqlite у которого LIKE работает регистронезависимо для русского текста в кодировке UTF-8

P.S.
Функции upper, lower, работу с regexp-ами не проверял (сейчас не до того), но думаю, будет работать...
Записан

Человеческая глупость дает представление о бесконечности
(с) Иоанна Хмелевская
nata267
Гость
« Ответ #5 : Январь 13, 2011, 11:33 »

я под виндоус программирую подключила sqlite3.dll, но у меня программа вылетает на строчке
int res = sqlite3_enable_load_extension(handle,1);
Записан
DmP
Гость
« Ответ #6 : Январь 13, 2011, 12:26 »

я под виндоус программирую подключила sqlite3.dll, но у меня программа вылетает на строчке
int res = sqlite3_enable_load_extension(handle,1);
Под виндой, плагин для sqlite по умолчанию собирается вместе с самой sqlite, поэтому нужно убедится в том, что Qt собрана с опцией -system-sqlite, иначе будет кощунство.
Записан
nata267
Гость
« Ответ #7 : Январь 13, 2011, 12:54 »

я под виндоус программирую подключила sqlite3.dll, но у меня программа вылетает на строчке
int res = sqlite3_enable_load_extension(handle,1);
Под виндой, плагин для sqlite по умолчанию собирается вместе с самой sqlite, поэтому нужно убедится в том, что Qt собрана с опцией -system-sqlite, иначе будет кощунство.

да, это понятно что собирается с sqlite, но регистронезаисимый like для русских букв все равно не работает, говорян нужно подключать какое-то icu расширение
Записан
Termit
Самовар
**
Offline Offline

Сообщений: 144



Просмотр профиля WWW
« Ответ #8 : Январь 13, 2011, 12:56 »

да, это понятно что собирается с sqlite, но регистронезаисимый like для русских букв все равно не работает, говорян нужно подключать какое-то icu расширение

ICU = International Components for Unicode

http://icu-project.org/download/4.0.html
Записан

Человеческая глупость дает представление о бесконечности
(с) Иоанна Хмелевская
Termit
Самовар
**
Offline Offline

Сообщений: 144



Просмотр профиля WWW
« Ответ #9 : Январь 13, 2011, 13:19 »

Что касается самого подключения...

Как минимум libSqliteIcu.so в Windows должна выглядеть как libSqliteIcu.dll

Типа такого 
Код:
res = sqlite3_load_extension(handle,"libSqliteIcu.dll",0,0);
Возможно даже не просто название dll, а вместе с путем, относительным или абсолютным

А ее нужно либо найти, либо собрать самой... И имя у этой библиотеки может быть любое
Записан

Человеческая глупость дает представление о бесконечности
(с) Иоанна Хмелевская
nata267
Гость
« Ответ #10 : Январь 14, 2011, 12:36 »

 Обеспокоенный не могу ни собрать ни найти эту библиотеку, скачала исходники, но там какая то хрень, скачала бинарники, то же самое
Записан
nata267
Гость
« Ответ #11 : Январь 17, 2011, 16:38 »

не подскажете какие файлы нужны для компиляции этого расширения кроме icu.c
Записан
Termit
Самовар
**
Offline Offline

Сообщений: 144



Просмотр профиля WWW
« Ответ #12 : Январь 17, 2011, 16:57 »

не подскажете какие файлы нужны для компиляции этого расширения кроме icu.c

Чем будете собирать?
Записан

Человеческая глупость дает представление о бесконечности
(с) Иоанна Хмелевская
nata267
Гость
« Ответ #13 : Январь 17, 2011, 17:01 »

я пытаюсь mingw, но я пытаюсь проект сделать в qt creator - вот pro файл:

Код:
TARGET	 = libSqliteIcu
TEMPLATE = lib
CONFIG += shared release

INCLUDEPATH += . \
    include \
    src

DEPENDPATH += include \
    src

LIBS += -L./lib -licuin38 \
    -L./lib -licuuc38 \
    -L./lib -licudt38 \
    -L./lib -licule38 \
    -L./lib -liculx38 \
    -L./lib -licutest \
    -L./lib -licutu38

HEADERS = sqliteicu.h \
        sqlite3.h \
        sqlite3ext.h \
        unicode/utypes.h \
        unicode/uregex.h \
        unicode/ustring.h \
        unicode/ucol.h

SOURCES = icu.c \
        sqlite3.c \
        shell.c

у меня ошибки вылазят при компиляции:

Creating library file: release\liblibSqliteIcu.a
release/icu.o(.text+0x5c):icu.c: undefined reference to `_imp__utf8_countTrailBytes_44'
release/icu.o(.text+0x8d):icu.c: undefined reference to `_imp__utf8_countTrailBytes_44'
release/icu.o(.text+0x115):icu.c: undefined reference to `_imp__utf8_countTrailBytes_44'
release/icu.o(.text+0x18a):icu.c: undefined reference to `u_foldCase_44'
release/icu.o(.text+0x19a):icu.c: undefined reference to `u_foldCase_44'
release/icu.o(.text+0x263):icu.c: undefined reference to `_imp__utf8_countTrailBytes_44'
release/icu.o(.text+0x29e):icu.c: undefined reference to `_imp__utf8_countTrailBytes_44'
release/icu.o(.text+0x4f2):icu.c: undefined reference to `utf8_nextCharSafeBody_44'
release/icu.o(.text+0x52a):icu.c: undefined reference to `u_errorName_44'
release/icu.o(.text+0x605):icu.c: undefined reference to `uregex_setText_44'
release/icu.o(.text+0x641):icu.c: undefined reference to `uregex_matches_44'
release/icu.o(.text+0x690):icu.c: undefined reference to `uregex_open_44'
release/icu.o(.text+0x6c5):icu.c: undefined reference to `uregex_setText_44'
release/icu.o(.text+0x7ef):icu.c: undefined reference to `u_strToUpper_44'
release/icu.o(.text+0x84d):icu.c: undefined reference to `u_strToLower_44'
release/icu.o(.text+0x90b):icu.c: undefined reference to `ucol_strcoll_44'
release/icu.o(.text+0x9db):icu.c: undefined reference to `ucol_open_44'
release/icu.o(.text+0xa51):icu.c: undefined reference to `ucol_close_44'
release/icu.o(.text+0x595):icu.c: undefined reference to `uregex_close_44'
release/icu.o(.text+0x8c5):icu.c: undefined reference to `ucol_close_44'
Записан
nata267
Гость
« Ответ #14 : Январь 17, 2011, 17:03 »

я вообщето dll ки никогда не собирала, что называется изучаю с нуля
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.185 секунд. Запросов: 23.