О работе с русскими буквами в InterBase/Firebird

Не пугайтесь объема этого текста ! На самом деле здесь перечислены абсолютно все темы, касающиеся "русификации" Borland InterBase и Firebird. Вам могут понадобиться только некоторые, но сначала прочитайте весь документ, а затем используйте нужное.

Установка

Начнем с того, что самая главная проблема при работе с русскими буквами в IB Database под Windows95 и Windows NT - известная ошибка версии 4.2, когда IB устанавливается в путь, содержащий пробелы, например "C:\Program Files\Intrbase". Даже если вы выполните все нижеследующие рекомендации, русские буквы не будут доступны пока вы не переустановите Borland InterBase например в "C:\Intrbase". Это относится к Local IB и IB for Windows95, но не к IB for NT (т.к. этот продукт устанавливается как раз в путь без пробелов). В Delphi 3.0 или C++Builder процесс переустановки облегчается тем, что IB устанавливается отдельно от средства разработки.
(примечание: не следует думать, что русскоязычные пользователи дискриминированы американской компанией - точно такие-же проблемы испытывают немцы, французы, итальянцы и все те, кто пишет не по английски).

Версия IB 5 и 6 хоть и свободна от этой ошибки, в некоторых случаях при операции restore базы данных наблюдается ошибка "text subtype52 not located" (или похожая).

Далее практически все, что будет изложено, можно прочитать как в IB32.HLP, так и в документации Borland InterBase Language Reference, раздел Character sets and collation orders (и не только там).

Создание базы данных

Теперь, когда вы переустановили Borland InterBase, настало время для создания базы данных. Получить возможность работы с русскими буквами в базе данных можно двумя способами: обычным и не используя кодировки.

  • Обычный способ: Работая на любой платформе вы должны при создании БД указать дополнительный параметр DEFAULT CHARACTER SET WIN1251. Если вы создаете БД в WISQL, то эту фразу вписываете в memo-поле Database Options, а если то-же самое делаете в командной строке ISQL - используйте полный синтаксис CREATE DATABASE "C:/MYDIR/MYDATABASE.GDB" USER "SYSDBA" PASSWORD "masterkey" DEFAULT CHARACTER SET WIN1251;
    Для BDE следует использовать настройки, указанные в разделе "Работа через BDE", который можно прочитать ниже.

    примечание: эквивалентом character set WIN1251 является кодировка CYRL, однако использовать ее не рекомендуется, т.к. она не поддерживает UPPER.

    На самом деле указание DEFAULT CHARACTER SET для базы данных означает только одно - что при создании таблиц для строковых полей (CHAR и VARCHAR) будет по умолчанию использоваться указанный как default набор символов. Не более того. Собственно, если вы хотите, можете не указывать default character set при создании базы данных, а вместо этого в каждом операторе create table, view, procedure и trigger для строковых полей и переменных в объявлении дописывать CHARACTER SET WIN1251.

  • Не используя кодировки: создавая БД НЕ указывать DEFAULT CHARATER SET ни для базы данных ни для символьных полей. В этом случае в BDE должен быть указан параметр LANGDRIVER: на странице SYSTEM - ascii ansi, DRIVERS - пусто, ALIAS - пусто. В этом случае в БД можно записывать символы в любой кодировке.

    Способ с отказом от кодировок более прост, позволяет работать с разными наборами символов в одном коннекте (например для web), но не может обеспечивать правильную сортировку различных наборов символов - перед использованием такого подхода нужно все тщательно проверить. Например, не будет работать функция UPPER и collation orders - вместо этого придется использовать функции из модуля CASEUDF.

     

    Вся остальная часть этого документа относится только к официальному способу работы с русскими буквами в IB

    ! Не стоит пытаться именовать таблицы, поля или любые другие объекты БД русскими буквами. Это не соотвествует стандарту, точно также как и при именовании типов или переменных в языках программирования Pascal или C. В общем это относится и к Interbase 6/Firebird, где в диалекте 3 можно указывать имена объектов, заключенные в двойных кавычках.

    Если вы создали таблицу, и хотите добавить туда несколько записей прямо из WISQL, стоит отсоединиться от БД и подсоединиться опять предварительно установив в "WISQL/Session/Advanced Settings/Character set on" тот самый WIN1251.

     

    Работа через BDE

    После создания БД можно настроить BDE. Для этого достаточно на страничке System, для драйвера INTRBASE (чтобы потом не делать то-же самое каждый раз при создании нового псевдонима) и для псевдонимов INTRBASE установить параметр LANGUAGE DRIVER = Pdox ANSI Cyrillic. Paradox тут ни при чем, просто так называется перекодировщик для кодовой таблицы 1251. Альтернативное название этого языкового драйвера (для указания в SQL Explorer из Delphi 2.0 или Database Desktop/Alias Manager) - ancyrr. Чтобы совсем не запутаться, для конфигурации псевдонимов в Delphi 2.0 для первого раза используйте BDECFG32.EXE - список выбора не даст вам ошибиться. А в Delphi 3.0 даже в SQL Explorer используется теперь тот-же список выбора языкового драйвера. В общем, Pdox ANSI Cyrillic - и никаких проблем.

    ! В списке кодировок Borland InterBase есть еще одна русскоязычная - CYRL (866). Однако уже давно Borland не выпускает никаких средств работы с IB из DOS, поэтому работая в Windows использовать кодировку 866 было-бы странно.  

    Работа через другие компоненты и API

    Здесь неважно, какой именно набор компонент используется - IBObjects, FreeIBComponents, FIBPlus или IBX. Нужно в параметрах компонента, отвечающего за соединение (XXDatabase), вписать строку

    lc_ctype=WIN1251 

    Если же речь идет об инструментах для работы с IB, работающих без BDE, то они должны поддерживать указание нужной кодировки ДО коннекта к базе данных. Например, IBConsole приобрела такую возможность начиная с 319-ой версии.

    Скрипты и ISQL

    Собственно, все то же самое. Т.е. кодировку символов нужно указать перед коннектом или созданием базы данных. Буквально - в начале скрипта написать:

    SET NAMES WIN1251;

    Эта же команда выдается интерактивно перед коннектом к БД через утилиту командной строки ISQL.

     

    Uppercase русских букв

    На этом можно было-бы закончить, если-бы иногда не хотелось производить поиск по uppercase строковых полей. Дело в том, что WIN1251 не имеет таблицы перевода строчных букв в прописные для русского языка. Зато ее collation order PXW_CYRL - имеет.

    Строковые типы полей CHAR и VARCHAR имеют специальные параметры дл указания набора хранимых символов и порядка сортировки. Когда база данных создана в определенном DEFAULT CHARACTER SET, этот CHARACTER SET добавляется автоматически ко всем объявлениям строковых полей при создании таблиц. При этом, напомню, CHARACTER SET WIN1251 не имеет таблицы uppercase. Для того, чтобы она была, нужно к объявлению поля добавить фразу COLLATE. Давайте сделаем тестовую таблицу:

    CREATE TABLE TESTCHAR(
    ID INTEGER NOT NULL PRIMARY KEY,
    NAME1 CHAR(30),
    NAME2 CHAR(30) COLLATE PXW_CYRL)

    И занесем в эту таблицу (хотя бы при помощи SQL Explorer) следующие данные:

    1 А А
    2 Б Б
    3 В В
    4 а а
    5 б б
    6 в в
    Теперь, выполните три запроса, и посмотрите в каком порядке будут возвращаться записи

    1) SELECT * FROM TESTCHAR ORDER BY NAME1
    2) SELECT * FROM TESTCHAR ORDER BY NAME2
    3) SELECT * FROM TESTCHAR ORDER BY NAME1 COLLATE PXW_CYRL

    Обратите внимание, что второй и третий запросы привели к одинаковому порядку записей в результате. Действительно, в любом месте и в любой ситуации можно добавить спецификатор COLLATE PXW_CYRL, если при создании таблицы у строкового поля этот спецификатор указан не был.

    Например, если нужно сделать поиск по uppercase-значению, даже когда поле было создано без collate -
    SELECT * FROM TESTCHAR WHERE UPPER(NAME1 COLLATE PXW_CYRL) = 'А'

    Естественно, что для поля NAME2 такая конструкция не понадобится, и совершенно нормально отработает запрос
    SELECT * FROM TESTCHAR WHERE UPPER(NAME2) = 'А'

    Примечание: если у вас есть индекс по полю NAME2, то использование любой функции (UPPER, или подключенных UDF) приведет к тому, что оптимизатор не сможет использовать индекс для ускорения запроса. В этом случае запрос SELECT * FROM TESTCHAR WHERE NAME2 = 'А' будет оптимизирован (поиск по индексу), а запрос SELECT * FROM TESTCHAR WHERE UPPER(NAME2) = 'А' приведет к перебору всех записей таблицы. Если у вас много записей в подобной таблице, и всего одно условие WHERE, содержащее UPPER, то вы можете добавить в таблицу дополнительное поле с DEFAULT UPPER(SOURCEFIELD). В этом случае новые значени добавляются только в SOURCEFIELD, а поиск ведется по полю, содержащему готовый UPPER.

    Примечание: указание COLLATE PXW_CYRL приводит к тому, что IB считает такие поля хранящими символы в 3-байтовой кодировке, и не позволяет создать индекс по такому полю если его длина превышает 84 (252/3=84) символа. В таком случае лучше отказаться от стандартного UPPER, и использовать собственные UDF для перевода регистра букв. Пример функций UpCase и LoCase с исходным текстом на Delphi и готовой DLL можно взять здесь - caseudf.zip (10K). В общем, указывать COLLATE PXW_CYRL или нет, вы должны решить для себя самостоятельно. В основном выбор определяется необходимостью специфической сортировки прописных и строчных русских букв, которую обеспечивает COLLATE PXW_CYRL (см. выше запросы с order by).

     

    Как сменить COLLATE на работающей базе данных

    Действительно, что делать если база данных уже работает, поля были созданы без указания COLLATE, а вдруг для какого-то поля понадобилось использовать функцию UPPER? Выход есть, и он более прост чем например изменение длины строкового поля.

    Примечание: вы должны помнить, что в простейшем случае такая задача решается написанием
    SELECT * FROM MYTABLE
    WHERE UPPER(MYFIELD COLLATE PXW_CYRL) = 'ВАСЯ'

    То же самое относится и к ORDER BY COLLATE PXW_CYRL. Таким образом, все изложенное ниже стоит использовать только в крайнем случае, когда никакие другие стандартные методы не работают.

    Для этого вам понадобится отредактировать системную таблицу RDB$RELATION_FIELDS. Первые два столбца этой таблицы - RDB$FIELD_NAME и RDB$RELATTION_NAME, т.е. имя поля и имя таблицы соответственно. Найдите запись, у которой эти поля имеют нужное вам значение - например MYFIELD и MYTABLE.

    Последний столбец таблицы RDB$RELATION_FIELDS называется RDB$COLLATION_ID. В нем записан 0, если поле имеет только CHARACTER SET WIN1251, и 1 - если поле было создано с CHARACTER SET WIN1251 COLLATE PXW_CYRL.

    Поэтому просто поменяйте 0 на 1, но только там, где RDB$COLLATION_ID не имеет значения "пусто".

    Теперь, чтобы существующие в таблице записи получили новый COLLATE, нужно сделать

    UPDATE MYTABLE
    SET MYFIELD=MYFIELD

    иначе UPPER будет работать только для вновь создаваемых записей, но не для старых - это вызвано тем, что InterBase хранит информацию о типах полей в blob таблицы RDB$FORMATS, что позволяет менять тип поля, длину, и например COLLATE прямо "на ходу".

    Ну и чтобы проверить, правильно-ли работает UPPER, можно выдать запрос

    SELECT UPPER(MYFIELD) FROM MYTABLE

    Если вы хотите изменить "одним махом" COLLATE у всех полей вашей БД, то можете выполнить запрос

    UPDATE RDB$RELATION_FIELDS
    SET RDB$COLLATION_ID = 1
    WHERE
    (RDB$FIELD_NAME NOT CONTAINING '$') AND
    (RDB$SYSTEM_FLAG = 0) AND
    (RDB$COLLATION_ID = 0)

    Затем, естественно, update придется выполнить для каждой таблицы, в которой вы хотите для строковых полей работать с UPPER. Если по измененным строковым полям есть индексы, то нужно эти индексы удалить и пересоздать, т.к. order by будет использовать для сортировки значения ключа, а не значения поля в таблице.

    примечание: изменение системных таблиц является нормальной операцией, если вы точно знаете что хотите сделать, и ознакомились с разделом System Tables в книге InterBase Language Reference. InterBase может выполнять изменение структуры таблиц, типов полей и т.п. операции, однако для них нет соответствующих команд SQL - они просто не определены в стандарте.

       

    ODBC-драйвер

    Для нормальной работы нужен ODBC-драйвер Intersolv, который входит в поставку IB 5.5, 5.6 или драйвер EasySoft, поставляемый отдельно. Эти драйверы позволяют установить на уровне настроек нужную кодировку, например WIN1251. Отдельно драйвер Intersolv не продается, не поставляется, и более не поддерживается с момента выхода Interbase 6.

    Работа с русскими буквами через ODBC-драйвер из версий IB 4.2, 5.0 и 5.1.1 будет проблемной. Этот драйвер НЕ позволяет установить кодировку принимаемых и передаваемых символов. Если на чтение ODBC-драйвер работает (и автономно и через BDE) нормально, то на запись - приходится формировать запрос вручную и добавлять специфическое указание используемого набора символов. Например, для той-же таблицы TESTCHAR, вставку записей придется писать при помощи UpdateSQL:
    INSERT INTO TESTCHAR VALUES (:ID, _win1251 :NAME1, _win1251 :NAME2)

    Напомню, что драйвер версии 3.0, поставляемый с IB 5.5/5.6, корректно работает с русскими буквами и кодировкой БД WIN1251.

     

    Русские буквы в хранимых процедурах, триггерах и exceptions

    Не возбраняется, однако будут некоторые проблемы. Дело в том, что все метаданные хранятся в универсальной многоязычной кодировке UNICODE_FSS. Поэтому, при создании триггеров и хранимых процедур, содержащих в тексте русские буквы, рекомендуется
  • делать это из WISQL, перед подсоединением к БД установив Character set on WIN1251
  • перед извлечением метаданных в WISQL (Extract Metadata for database), опять-же до подсоединения к БД нужно установить Character set on UNICODE_FSS
  • если это возможно, избавиться от строковых констант с русскими буквами в теле триггера или процедуры. Для процедуры, например, можно передавать строку с русскими буквами как параметр - это в дальнейшем может избавить вас и от переписывания этой процедуры.
  • В SQL Explorer при попытке просмотра таких процедур, триггеров и exceptions будет возникать exception о "неверном преобразовании символов". Это решается созданием отдельного алиаса с пустым LANGDRIVER специально для работы с метаданными. Т.е. в алиасе с Pdox ansi Cyrillic вы работаете с данными, а в алиасе без языкового драйвера - с "русскими" exceptions, комментариями и текстом в триггерах и процедурах.

     

    Не надо

    Из-за ошибки в GBAK (вплоть до IB 6.0 включительно) не рекомендуется использовать в качестве списка допустимых значений для строковых полей русские буквы при описании структуры таблицы (default value list). Лучше перенести эту часть в триггер, если такая проверка действительно необходима на сервере. Если-же все-таки это случилось, восстановить базу данных удастся только при установленном параметре GBAK Do not restore validity conditions (в противном случае БД не восстановится, см Verbose Output).

    В Firebird версии 0.9.5.156 и выше этот баг устранен, однако чтобы он не возникал, требуется создание базы данных именно в этой версии. Backup/Restore для исправления бага недостаточно.

    Еще один вариант решения проблемы с русскими default - это создание их в следующей форме:

    create table bug_bugbase (
    s varchar(20) character set win1251 collate win1251
    default _win1251 'XXXX'
    not null);

    Это даст указание однозначно идентифицировать character set для символов, указываемых в default.

    Подключение своих наборов символов

    Такая возможность есть, и она включая примеры описана в CollateKit и ibCollate на http://www.brookstonesystems.com/. Однако перед публикацей исходников IB в OpenSource при вычистке кода, управляющего лицензиями, была допущена ошибка, в результате чего CollateKit до сих пор не работал ни с бесплатным Interbase ни с Firebird. В билде Firebird старше ~1.0.0.500 эта ошибка устранена, и кодировки можно подключать. Однако при этом под Windows надо внимательно следить за версией файла GDSINTL.DLL (под Unix - gdsintl.so) - она должна точно совпадать с версией Firebird, в противном случае кодировки работать не будут (вообще, даже не имея в виду создаваемые самостоятельно кодировки).

  • Кузьменко Дмитрий, http://ib.demo.ru.



    Опубликовал admin
    2 Сен, Четверг 2004г.



    Программирование для чайников.