На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! информация о разделе
user posted imageДанный раздел предназначается исключительно для обсуждения вопросов использования языка запросов SQL. Обсуждение общих вопросов, связанных с тематикой баз данных - обсуждаем в разделе "Базы данных: общие вопросы". Убедительная просьба - соблюдать "Правила форума" и не пренебрегать "Правильным оформлением своих тем". Прежде, чем создавать тему, имеет смысл заглянуть в раздел "Базы данных: FAQ", возможно там уже есть ответ.

Модераторы: Akina
  
> SQLite и Unicode без ICU , Простой патч с использованием WinAPI
    В движке БД SQLite функции UPPER, LOWER, LIKE и GLOB по умолчанию работают только с латинским алфавитом. Для того, чтобы обеспечить нормальную их работу с юникодными символами, SQLite можно собрать с поддержкой библиотеки ICU (дефайн SQLITE_ENABLE_ICU). Однако, для систем где по умолчанию нет ICU это добавляет пару лишних десятков мегабайт, что может быть неприемлемо для компактных утилит и использовании в различных embedded-системах. Так, как в WinAPI (и других API/фрэймворках) есть свои функции для работы со строками, можно использовать их.
    Ниже привожу описание своего простенького windows-only патча:

    Патчим работу SQL-функций UPPER и LOWER - за них отвечают upperFunc и lowerFunc:
    • так, как они теперь работают с юникодом, то меняем вызовы sqlite3_value_text/sqlite3_value_bytes/sqlite3_result_text на аналогичные, но с цифрой 16 в конце.
    • вставляем вызовы CharUpperW/CharLowerW*
    ExpandedWrap disabled
      static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
        char *z1;
        const char *z2;
        int i, n;
        UNUSED_PARAMETER(argc);
        z2 = (char*)sqlite3_value_text16(argv[0]);
        n = sqlite3_value_bytes16(argv[0]);
        /* Verify that the call to _bytes() does not invalidate the _text() pointer */
        assert( z2==(char*)sqlite3_value_text16(argv[0]) );
        if( z2 ){
          z1 = contextMalloc(context, ((i64)n)+1);
          if( z1 ){
            memcpy(z1, z2, n);
            CharUpperW((LPWSTR)z1);
            sqlite3_result_text16(context, z1, n, sqlite3_free);
          }
        }
      }
      static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
        char *z1;
        const char *z2;
        int i, n;
        UNUSED_PARAMETER(argc);
        z2 = (char*)sqlite3_value_text16(argv[0]);
        n = sqlite3_value_bytes16(argv[0]);
        /* Verify that the call to _bytes() does not invalidate the _text() pointer */
        assert( z2==(char*)sqlite3_value_text16(argv[0]) );
        if( z2 ){
          z1 = contextMalloc(context, ((i64)n)+1);
          if( z1 ){
            memcpy(z1, z2, n);
            CharLowerW((LPWSTR)z1);
            sqlite3_result_text16(context, z1, n, sqlite3_free);
          }
        }
      }

    *Примечание: В WinAPI функции CharUpperW/CharLowerW работают как с одиночными символами, так и с целыми строками, в зависимости от того, что им передается - 2-байтный символ или указатель на строку (который будет больше 0xffff).

    Патчим функции LIKE и GLOB - тут очень просто:
    Ищем
    ExpandedWrap disabled
      # define GlobUpperToLower(A)   if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; }

    и меняем на
    ExpandedWrap disabled
      # define GlobUpperToLower(A)   if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } else { A = CharLowerW((LPWSTR)(A & 0xFFFF)); }

    Примечание: в ранних версиях SQLite 3, данный дефайн почему-то называется GlogUpperToLower

    Осталось сделать COLLATE NOCASE - правим nocaseCollatingFunc:
    ExpandedWrap disabled
      static int nocaseCollatingFunc(
        void *NotUsed,
        int nKey1, const void *pKey1,
        int nKey2, const void *pKey2
      ){
        int r = CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pKey1, -1, pKey2, -1);
       
        switch(r)
        {
        case CSTR_LESS_THAN   : return -1;
        case CSTR_EQUAL       : return  0;
        case CSTR_GREATER_THAN: return  1;
        default               : return  0;
        }
      }


    Так, как теперь nocaseCollatingFunc работает с юникодными строками, ищем место, где она регистрируется и исправляем:
    меняем
    ExpandedWrap disabled
      /* Also add a UTF-8 case-insensitive collation sequence. */
      createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);

    на
    ExpandedWrap disabled
      /* Also add a UTF-16 case-insensitive collation sequence. */
      createCollation(db, "NOCASE", SQLITE_UTF16, 0, nocaseCollatingFunc, 0);


    По такому же принципу можно пропатчить SQLite для использования не только с WinAPI, но и с другими API - нам только нужны юникодные функции для:
    • перевода символа/строки в верхний/нижний регистр
    • сравнения двух строк

    По ссылке можно скачать измененный исходник для версии 3.8.3 и собранную dll.
    https://drive.google.com/file/d/0Bzw1xBVt0m...dit?usp=sharing
    В аттаче diff для той же версии 3.8.3
    Прикреплённый файлПрикреплённый файлsqlite3.c.3_8_3.diff (2,28 Кбайт, скачиваний: 543)
    Сообщение отредактировано: mitrich -
      Спасибо огромное за скомпиленный dll, а то днем с огнем не сыщешь )

      Я правильно понимаю, что ICU по умолчанию всегда присутствует в Windows ?
        Цитата DriveSoft @
        Я правильно понимаю, что ICU по умолчанию всегда присутствует в Windows ?

        Как раз таки она по умолчанию в Windows всегда отсутствует.
          Спасибо, НО для версии 3.8.7 этот патч не подходит, да и код в функциях отличается от 3.8.3, очень прошу сделать такой патч для версии 3.8.7, с описанием где что менять.
            Действительно, в версии 3.8.7 переделали функцию patternCompare и дефайн GlobUpperToLower больше не используется. А вот upperFunc, lowerFunc и nocaseCollatingFunc остались такими же.
            Чуть позже выложу патч для последней версии SQLite.
              mitrich
              Можешь написать подробно, чем и как компилил sqlite.
                Вроде так (буду дома, посмотрю точнее):
                ExpandedWrap disabled
                  gcc -o sqlite3.dll -shared -O2 -DSQLITE_ENABLE_FTS4
                  Помогите с sqlite.dll для последних релизов sqlite-dll-win32-x86-3.08.11.01
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0288 ]   [ 16 queries used ]   [ Generated: 3.05.24, 19:09 GMT ]