вторник, 26 июня 2012 г.

PostgreSQL: текстовой поиск + латышский язык

Дано: PostgreSQL 8.3.1.

Задача: реализовать поиск по тексту независимым от латышских диакритических символов. Т.е. по запросу «ē», должны быть найдены и «e», и «ē» и наоборот. 

Латышский язык содержит следующие диакритические знаки (wikipedia):
  1. гарумзиме: ā ē ī ū,
  2. гачек: č š ž,
  3. седиль: ģ ķ ļ,
и всем этим буквам соотвествуют обычные латинские, без дополнений.

Сначала, для тех кто ищет просто решение - функция, которая заменяет буквы с диакритическими знаками на обычные:

CREATE OR REPLACE FUNCTION unaccent_string(text)
RETURNS text
 LANGUAGE SQL
 IMMUTABLE
 STRICT
AS $$

SELECT replace(
  replace(
   replace(
    replace(
     replace(
      replace(
       replace(
        replace(
         replace(
          replace(
           replace(
(
 SELECT replace(
   replace(
    replace(
     replace(
      replace(
       replace(
        replace(
         replace(
          replace(
           replace(
            replace($1, \'ā\', \'a\'),
            \'ž\', \'z\'),
           \'ū\', \'u\'),
          \'š\', \'s\'),
         \'ņ\', \'n\'),
        \'ļ\', \'l\'),
       \'ķ\', \'k\'),
      \'ī\', \'i\'),
     \'ģ\', \'g\'),
    \'ē\', \'e\'),
   \'č\', \'c\') AS "text")

            , \'Ā\', \'A\'),
           \'Ž\', \'Z\'),
          \'Ū\', \'U\'),
         \'Š\', \'S\'),
        \'Ņ\', \'N\'),
       \'Ļ\', \'L\'),
      \'Ķ\', \'K\'),
     \'Ī\', \'I\'),
    \'Ģ\', \'G\'),
   \'Ē\', \'E\'),
  \'Č\', \'C\') AS "text";
$$;

Не имея понятия с чего начать, я попытался найти какое-то готовое решение. Мне попалась идея замены букв на обычные с помощью функции translate(). Отсюда и начал:

~~
SELECT translate('Cātozzo', 't', 'a2') AS "res"

res: Cāaozzo
~~

простой символ заменяется как и ожидалось, но:

~~
SELECT translate('Cātozzo', 'ā', 'a2') AS "res"

res: Ca2tozzo
~~

utf-символ воспринимается функцией translate как два, и каждая половинка заменяется отдельно (таков принцип работы функции). Первая часть utf-символа повторяется у разных букв, поэтому вариант с translate() не работает или сильно усложняется.

Тогда я решил попробовать replace, что и дало мне функцию указанную вначале статьи. Тест:

~~
SELECT unaccent_string(\'glāžšķūņu rūķīši\') AS "res"

res: glazskunu rukisi

SELECT unaccent_string(\'GLĀŽŠĶŪŅU RŪĶĪŠI\') AS "res"

res: GLAZSKUNU RUKISI
~~


пятница, 1 июня 2012 г.

Удалённое использование Git под Windows


Моя первая запись в этом блоге, поэтому: Здравствуйте!

Эта статья о первом опыте удалённой работы с GIT версии 1.7.10 под Windows.

Всё моё знакомство с системами контроля версий ограничивалось Subversion + TortoiseSVN. В связи с некоторыми последними изменениями в сервере Subversion, было решено попробовать что-то другое. Как альтернативу (первое что попалось) я выбрал Git.

Наиболее важным открытием для меня стало то, что у GIT нет такого централизованного репозитория как у Subversion. Каждый репозиторий GIT сам по себе, и может принимать и отсылать изменения в/из любых доступных его копий.

Так как это мой первый опыт, то при установке я оставил все опции по умолчанию.

Примитивные команды GIT на локальном компьютере проблем не составляют. А вот при удалённом использовании уже возникают некоторые вопросы. И первый из них это протокол. Т. е. как посылать команды на удалённый компьютер. Есть несколько вариантов (англ. http://git-scm.com/book/ch4-1.html) из которых я выбрал SSH за безопасность.

Значит нужен SSH-сервер. После небольшого поиска я установил Bitwise WinSSHD (http://www.bitvise.com/) бесплатный для некомерческого использования. WinSSHD практически не требует настройки, кроме добавления пользователя и изменения способа выполнения получаемых команд (об этом расскажу ниже).

Вопрос протокола решён (настройка фаервола и роутера останется за кадром). Теперь надо разобраться с тем как передать команду с удалённого компьютера. Вот это и доставило мне больше всего проблем.

Команду клонирования удалённого репозитория я запускаю через Git Bash. В моём случае она выглядит следующим образом:

git clone ssh://ssh_user@home/d:/dev/git_repo .
, где
  • home – адрес удалённого компьютера
  • d:/dev/git_repo – путь к репозиторию на удалённом компьютере
  • . (точка) — указывает на то что репозиторий будет клонироваться в текущую папку

К сожалению команда не работает... Я получил следующую ошибку:

'git-upload-pack' is not recognized as an internal or external command.

По русски это значит что на удалённом компьютере не найдена программа 'git-upload-pack'. Для исправления ситуации идём на удалённый компьютер, ищем где у нас расположена эта программа и добавляем путь в переменную PATH пользователя, под которым происходит выполнение команд в WinSSHD.

(Для команды git clone можно также использовать ключь —upload-pack для указания пути к git-upload-pack, но у меня это не вышло, возможно из-за неудобоваримых (для Bash) символов в пути к файлу.)

Одна проблема решена. Теперь выполнение команды прерывается без каких-либо полезных объяснений:

Самое время воспользоваться логами WinSSHD чтобы посмотреть как выполняются переданные команды. Тут нужно учесть, что WinSSHD использует время UTC.
Опять переключаемся на удалённый компьютер и в логе SSH-сервера находим запись выполняемой команды:

000000002132 2012-05-31 13:54:22.151924 UTC WinSSHD 5.26 [055] Info
Session thread 1195 for Windows account 'Home\remoteuser' from 192.168.0.51:12134:
Session channel 1: Executed command 'cmd.exe /c git-upload-pack '/d:/dev/git_repo'' in working
directory 'C:\Users\RemoteUser'.

Отсюда берём команду «cmd.exe /c git-upload-pack '/d:/dev/git_repo'», пробуем её выполнить в командной строке Windows и получаем:

Чтобы обойти эту проблему берём libiconv-2.dll из Git\bin и копируем его в Git\libexec\git-core .

При повторной попытке команда выполняется, но cmd.exe сообщает что не может найти путь /d:/dev/git_repo. Зато Git Bash понимает такой путь, следовательно нужно проинструктировать WinSSHD выполнять команды через Bash. Для этого:
  1. Добавляем путь к Git\bin в переменную PATH (там лежит sh.exe)
  2. Создаём файл cmdrouter.sh в котором всего два символа: $*. Этот файл будет перенаправлять все переданные команды к sh.exe)
  3. Заходим в расширенные настройки WinSSHD: Edit Advanced Settings -> Windows Accounts -> Edit, и убираем галочку «Use group default exec request prefix» и в поле «Exec request prefix» указываем как выполнять полученную команду:

cmd.exe /c sh cmdrouter.sh 

обратите внимание на пробел после команды, он нужен чтобы отделить строку которую получает WinSSHD от клиента. Сохраняем настройки.

Вот и все дела! Теперь удалённый репозиторий клонируется без проблем.