Поиск в SQLite без учета регистра, для русского языка

August 14th, 2010 Begemot

Не смотрю на всю свою юникодность, SQLite все-таки юникодна не до конца:( При поиске типа WHERE description LIKE “%STRING%” поиск идет без учета регистра для латинских букв, но к сожалению, он регистрозависимый для всех остальных символов. Корни этого уходят в виндовую функцию tolower(), которая правильно обрабатывает символы только текущей локали. И это весьма плохо, для целого ряда задач, например для поиска ранее скопированного текста в истории буфера обмена (извините, не удержался:))

Но к счастию способ есть. Оригинал и файлы для загрузки тут – SQLite and native UNICODE LIKE support in C/C++ . А я раскажу о том как это интегрировать и скрестить с wxDatabaselayer’om.

  1. Берем файлы sqlite3_unicode.h/c с архива по ссылке выше и добавляем в проект.
  2. Вызываем свойства sqlite3_unicode.c  и добавляем SQLITE_ENABLE_UNICODE; SQLITE_CORE в определения препроцессора c++/preprocessor/preprocessor definitions
  3. Если используете precompiled header в проекте, надо в свойствах обоих файлов отключить его использование.
  4. в с файле есть строчка #include “sqlite3.h” заменить ее на свой путь к sqlite3.h, если он у вас отличается
  5. Включить sqlite3.h в sqlite3_unicode.h, без этого у меня не компилилось.
  6. Дальше вызываете sqlite3_unicode_load();  \  sqlite3_unicode_free();  –  в начале/конце программы
  7. После открытия базы данных вызываем для нее sqlite3_unicode_init(db);

Проблема тут в том что sqlite3_unicode_init(db); хочет db типа sqlite3 *, а у нас есть только указатель на обьект датабайслаера. Тут придется править код самого wxDatabaselayer’a и заново компилить. Идем в databaselayer\include\SqliteDatabaseLayer.h, пишем:

// Added by Begemot – for using with  sqlite3_unicode
void * GetSQLiteDatabase()  { return m_pDatabase; } 

компиляем, и в нашей программе вместо строчки sqlite3_unicode_init(db); используем вот такую вот страшную конструкцию

sqlite3_unicode_init(static_cast<sqlite3*>(static_cast<SqliteDatabaseLayer*>(db)->GetSQLiteDatabase()));

Все. Теперь Like % прекрасно ищет по русским или любым другим символам без учета регистра.


Если пост полезен для вас вы можете подписаться на RSS или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.


Слушайте свою интуиции

March 30th, 2009 Begemot

Что отличает опытного разработчика от новичка? Правильно – хорошая интуиция 🙂

Только что ситуация на работе – надо написать сохранение проектов с которыми работает программа в базу данных. Как это все должно выглядеть обсудили еще в пятницу, начальник набросал табличку в которой все должно хранится. Я с утра сел – казалось бы куда проще – заимплементить дамп в бд, нескольких классов, учитывая что структура уже придумана и основной код сохранения в хмл написан.

Не работает, падает на pDB->PrepareStatement(…), убил 20 минут перепроверяя свои знания SQL, правильность написания полей и т.д. – все правильно, но не работает. Оказалось, что ему не нравится что одно из полей таблицы названо “Index”.  Не знаю в чем трабла в SQLite или в используемом враппере wxSqlite3, или еще в чем… но факт что падает на строке

st = pDB->PrepareStatement(_T(“INSERT INTO MMFrames (ProjectID, Index,  Type, Properties) VALUES (?, ?, ?, ?);”));

Пришлось переименовывать поле в таблице.

А весь юмор ситуации в том что, когда создавал бд – я подумал что лучше вместо Index назвать поле Position. Но решил что раз начальник написал Index, пусть так и будет. Потом подумал, что это поле вообще тут не нужно и хотел его удалить, но опять же решил оставить, раз на бумажке есть. Вообщем доверяйте своей интуиции.


Если пост полезен для вас вы можете подписаться на RSS или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.


Сюрпризы sqlite CURRENT_TIMESTAMP

December 13th, 2008 Begemot

Думаете достаточно просто определить стобец как

created TIMESTAMP not null default CURRENT_TIMESTAMP,

и забыть про него. В смысле не задавать значения этого поля при вставке, мол sqlite сама туда добавит текущее время? Напрасно 🙂

SQLite действительно сама занесет в него текущее время при вставке строки, но это будет время в UTC, без учета вашего смещения. В таком случае читать его надо как

SELECT datetime(created, 'localtime') FROM my_table; 

вместо обычного

SELECT created FROM my_table;

Но я думаю что лучше сразу правильно писать в дб, указывая значения для этого столбца как datetime(‘now’, ‘localtime’). В коде использованием SqliteDatabaseLayer, это будет выглядеть примерно так

PreparedStatement* pStatement = db->PrepareStatement(wxT(“INSERT INTO log (created, title) VALUES (datetime(‘now’, ‘localtime’), ?);”));

Больше про функции работы с датой в sqlite.

 

 


Если пост полезен для вас вы можете подписаться на RSS или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.