
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.14.88] |
![]() |
|
![]() | Данный раздел предназначается исключительно для обсуждения вопросов использования языка запросов SQL. Обсуждение общих вопросов, связанных с тематикой баз данных - обсуждаем в разделе "Базы данных: общие вопросы". Убедительная просьба - соблюдать "Правила форума" и не пренебрегать "Правильным оформлением своих тем". Прежде, чем создавать тему, имеет смысл заглянуть в раздел "Базы данных: FAQ", возможно там уже есть ответ. |
Сообщ.
#1
,
|
|
|
В движке БД SQLite функции UPPER, LOWER, LIKE и GLOB по умолчанию работают только с латинским алфавитом. Для того, чтобы обеспечить нормальную их работу с юникодными символами, SQLite можно собрать с поддержкой библиотеки ICU (дефайн SQLITE_ENABLE_ICU). Однако, для систем где по умолчанию нет ICU это добавляет пару лишних десятков мегабайт, что может быть неприемлемо для компактных утилит и использовании в различных embedded-системах. Так, как в WinAPI (и других API/фрэймворках) есть свои функции для работы со строками, можно использовать их.
Ниже привожу описание своего простенького windows-only патча: Патчим работу SQL-функций UPPER и LOWER - за них отвечают upperFunc и lowerFunc: ![]() ![]() 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 - тут очень просто: Ищем ![]() ![]() # define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } и меняем на ![]() ![]() # define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } else { A = CharLowerW((LPWSTR)(A & 0xFFFF)); } Примечание: в ранних версиях SQLite 3, данный дефайн почему-то называется GlogUpperToLower Осталось сделать COLLATE NOCASE - правим nocaseCollatingFunc: ![]() ![]() 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 работает с юникодными строками, ищем место, где она регистрируется и исправляем: меняем ![]() ![]() /* Also add a UTF-8 case-insensitive collation sequence. */ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); на ![]() ![]() /* 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 Прикреплённый файл ![]() |
Сообщ.
#2
,
|
|
|
Спасибо огромное за скомпиленный dll, а то днем с огнем не сыщешь )
Я правильно понимаю, что ICU по умолчанию всегда присутствует в Windows ? |
Сообщ.
#3
,
|
|
|
Цитата DriveSoft @ Я правильно понимаю, что ICU по умолчанию всегда присутствует в Windows ? Как раз таки она по умолчанию в Windows всегда отсутствует. |
Сообщ.
#4
,
|
|
|
Спасибо, НО для версии 3.8.7 этот патч не подходит, да и код в функциях отличается от 3.8.3, очень прошу сделать такой патч для версии 3.8.7, с описанием где что менять.
|
Сообщ.
#5
,
|
|
|
Действительно, в версии 3.8.7 переделали функцию patternCompare и дефайн GlobUpperToLower больше не используется. А вот upperFunc, lowerFunc и nocaseCollatingFunc остались такими же.
Чуть позже выложу патч для последней версии SQLite. |
Сообщ.
#6
,
|
|
|
mitrich
Можешь написать подробно, чем и как компилил sqlite. |
Сообщ.
#7
,
|
|
|
Вроде так (буду дома, посмотрю точнее):
![]() ![]() gcc -o sqlite3.dll -shared -O2 -DSQLITE_ENABLE_FTS4 |
Сообщ.
#8
,
|
|
|
Помогите с sqlite.dll для последних релизов sqlite-dll-win32-x86-3.08.11.01
|
Сообщ.
#9
,
|
|
|
mitrich, Благодарю вас за решение!
Воткнулся в эту проблему уже начав изучать исходник, и вдруг наткнулся на ваш пост, в общем на 3.46.1 решение работает, единственное что вот этой части нет: Цитата mitrich @ Патчим функции LIKE и GLOB - тут очень просто: Ищем # define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } и меняем на # define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } else { A = CharLowerW((LPWSTR)(A & 0xFFFF)); } Примечание: в ранних версиях SQLite 3, данный дефайн почему-то называется GlogUpperToLower без него так же все работает без нареканий, в общем респект уважуха и тому подобное ! |
Сообщ.
#10
,
|
|
|
Заменил в коде указанные фрагменты, при попытке скомпилировать sqlite.dll получил ошибку:
sqlite3.lo : error LNK2019: ссылка на неразрешенный внешний символ __imp_CharUpperW в функции upperFunc. sqlite3.lo : error LNK2019: ссылка на неразрешенный внешний символ __imp_CharLowerW в функции lowerFunc. Компилировал по инструкции с сайта SQLITE.ORG через MSVC 2022. Я новичок, это моя первая попытка, хотелось бы понять, что я делаю не так |