Russian Qt Forum

Qt => Базы данных => Тема начата: Termit от Сентябрь 24, 2010, 14:31



Название: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: Termit от Сентябрь 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 понимать регистронезависимый поиск в базе по русским словам?


Название: Re: SQLITE регистронезависимый LIKE
Отправлено: Termit от Сентябрь 24, 2010, 16:40
Собственно в FAQ (http://www.sqlite.org/faq.html#q18), который был процитирован, четко сказано, что данная ф-ция работает только для ASCII. Для прочих кодировок нужно писать свои функции like(), upper(), lower() и пр. Или как вариант собрать SQLITE с ICU.

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

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


Название: Re: SQLITE регистронезависимый LIKE
Отправлено: DmP от Сентябрь 24, 2010, 16:48
Собственно в FAQ (http://www.sqlite.org/faq.html#q18), который был процитирован, четко сказано, что данная ф-ция работает только для 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;
    }
  }
Попробуйте сделать так же.


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


Название: Re: SQLITE регистронезависимый LIKE
Отправлено: Termit от Сентябрь 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-ами не проверял (сейчас не до того), но думаю, будет работать...


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: nata267 от Январь 13, 2011, 11:33
я под виндоус программирую подключила sqlite3.dll, но у меня программа вылетает на строчке
int res = sqlite3_enable_load_extension(handle,1);


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: DmP от Январь 13, 2011, 12:26
я под виндоус программирую подключила sqlite3.dll, но у меня программа вылетает на строчке
int res = sqlite3_enable_load_extension(handle,1);
Под виндой, плагин для sqlite по умолчанию собирается вместе с самой sqlite, поэтому нужно убедится в том, что Qt собрана с опцией -system-sqlite, иначе будет кощунство.


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: nata267 от Январь 13, 2011, 12:54
я под виндоус программирую подключила sqlite3.dll, но у меня программа вылетает на строчке
int res = sqlite3_enable_load_extension(handle,1);
Под виндой, плагин для sqlite по умолчанию собирается вместе с самой sqlite, поэтому нужно убедится в том, что Qt собрана с опцией -system-sqlite, иначе будет кощунство.

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


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: Termit от Январь 13, 2011, 12:56
да, это понятно что собирается с sqlite, но регистронезаисимый like для русских букв все равно не работает, говорян нужно подключать какое-то icu расширение

ICU = International Components for Unicode

http://icu-project.org/download/4.0.html


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: Termit от Январь 13, 2011, 13:19
Что касается самого подключения...

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

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

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


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: nata267 от Январь 14, 2011, 12:36
 :-[ не могу ни собрать ни найти эту библиотеку, скачала исходники, но там какая то хрень, скачала бинарники, то же самое


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: nata267 от Январь 17, 2011, 16:38
не подскажете какие файлы нужны для компиляции этого расширения кроме icu.c


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: Termit от Январь 17, 2011, 16:57
не подскажете какие файлы нужны для компиляции этого расширения кроме icu.c

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


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: nata267 от Январь 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'


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: nata267 от Январь 17, 2011, 17:03
я вообщето dll ки никогда не собирала, что называется изучаю с нуля


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: virtual_root от Апрель 19, 2013, 09:26
Ребята, помогите пожалуйста! Я программирую под Linux(debian). Мне нужно организовать регистронезависимый LIKE в запросах.
Сделала как описано выше:
Цитировать
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 пункт не могу пройти...
для AMD 64
Код:
gcc -shared icu.c `icu-config --ldflags` -fPIC -o libSqliteIcu.so
у меня вылазит ошибка:
icu.c:1:1: error: expected identifier or ‘(’ before ‘<’ token
я выполняю 3 пункт из домашней директории, куда и скачала  icu.c, но не знаю как преодолеть эту ошибку..
Меня удивило содержание файла uci.c:
Код:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="/cvstrac.css" media="all">
<title>SQLite CVSTrac</title>
 
</head>
<body>
<div><!-- container div to satisfy validator -->

<div class="sqlite_header">
<a href="/index.html">
<img class="logo" src="/images/sqlite370_banner.gif" alt="SQLite Logo" border="0"></a>
<div><!-- IE hack to prevent disappearing logo--></div>
<div class="tagline">Small. Fast. Reliable.<br>Choose any three.</div>

<table width=100% style="clear:both"><tr><td>
  <div class="se"><div class="sw"><div class="ne"><div class="nw">
  <div class="toolbar">
    <a href="/about.html">About</a>
    <a href="/sitemap.html">Sitemap</a>
    <a href="/docs.html">Documentation</a>
    <a href="/download.html">Download</a>
    <a href="/copyright.html">License</a>
    <a href="/news.html">News</a>
    <a href="/cvstrac/index">Developers</a>
    <a href="/support.html">Support</a>
  </div></div></div></div></div>
</td></tr></table>
</div><div id="header">
<h1 id="title">
sqlite - Home Page
</h1>
<p id="identity">
<a href="honeypot"><notatag arg="meaningless"></a>
<a href="login?nxp=/cvstrac/index" title="Log in">Not logged in</a>
</p>
<ul id="navigation">
<li><a href="honeypot">Honeypot</a></li>
<li><a href="dir">Browse</a></li>
<li id="current"><a href="index">Home</a></li>
<li><a href="login">Login</a></li>
<li><a href="mainmenu">Main Menu</a></li>
<li><a href="reportlist">Reports</a></li>
<li><a href="search">Search</a></li>
<li><a href="timeline">Timeline</a></li>
<li><a href="wiki">Wiki</a></li>
</ul>
</div>
<div id="content">
<strong class="two">SQLite developer links:</strong>

<p><ul>
<li><a class="external" href="http://www.sqlite.org/src/tktnew">Report A Bug</a>
<li><a href="wiki">Wiki</a>
<li><a class="external" href="http://www.sqlite.org/src/timeline">Timeline</a>
<li><a class="external" href="http://www.sqlite.org/src/dir">Browse historical source files</a>
<li><a class="external" href="http://www.sqlite.org/docsrc">Documentation Sources</a>

<p><li><a href="wikiedit?p=HomePage">Edit this page</a>
   (registered developers only)</ul>
</div>
</div></body></html>
Может чего-то не хватает для выполнения пункта 3 ?
Подскажите пожалуйста!!!


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: Termit от Апрель 19, 2013, 10:17
Это скачалась html страничка. У файла, видимо, изменился адрес.
Прикрепляю к сообщению.


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: virtual_root от Апрель 19, 2013, 10:40
спасибо огромное!


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: virtual_root от Апрель 19, 2013, 11:21
всё наконец собралось и я получила файл libSqliteIcu.so. Но теперь проблема в следующем:
пробую выше приведенный кусок кода:
Код:
/*
         После того как базу данных открыли пишем
         */
         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);
           }
         }
Но у меня программа падает при вызове функции sqlite3_enable_load_extension(handle,1); с ошибкой сегментирования... Я закоментировала эту функцию, программа не падает. Подскажите пожалуйста почему это может быть? И как решить эту проблему?


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: Termit от Апрель 19, 2013, 12:03
Файл libSqliteIcu.so необходимо скопировать в какой-нить каталог в котором система ищет библиотеки. Я копирую в /usr/lib/
Код
Bash
sudo cp libSqliteIcu.so /usr/lib/

либо в каталоге /etc/ld.so.conf.d/
создать файл с расширением conf и прописать в нем полный путь к библиотеке. После этого запустить
Код
Bash
sudo ldconfig


Если это не поможет покажите полный код, может в нем что-то не так.


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: virtual_root от Апрель 19, 2013, 12:45
Не помогло.. По этой ссылке http://helper.program21.ru/wp-content/uploads/2013/04/SQLite_with_module_icu.zip (http://helper.program21.ru/wp-content/uploads/2013/04/SQLite_with_module_icu.zip) можно скачать мой проект. Помогите пожалуйста! Подскажите что я сделала не так?
Может у меня что-то с sqlite3 не так?


Название: Re: [SOLVED] SQLITE регистронезависимый LIKE
Отправлено: Termit от Апрель 20, 2013, 11:43
Необходимо привести в такой вид загрузку самого расширения. Изменения выделил отступами.

Код
C++ (Qt)
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)
                   sqlite3_load_extension(handle,"libSqliteIcu.so",0,0);
 }
}

Помимо этого в SQL запросе не нужно напрямую писать текст кириллицей. Лучше биндить параметры через bindValue, а сам текст делать через tr(). Ну или на крайняк использовать
Код
C++ (Qt)
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));