Утилита конвертации базы данных из Yaffil в Firebird (постановка)

Материал из GedeminWiki
Перейти к: навигация, поиск

Ссылка на страничку утилиты FDBConvert.


Утилита предназначена для конвертации существующей базы данных из формата серверов Yaffil, FB 1.5, FB 2.0, FB 2.1 в FB 2.5. Конвертация возможна как из командной строки, так и в интерактивном режиме.

Утилита решает следующие проблемы:

  • Апгрейд в новую структуру файла базы данных с конвертированием юникодовских данных (FIX_FSS_DATA, FIX_FSS_METADATA).
  • Замена всех внешних функций, для которых теперь есть аналогичные встроенные.
  • Замена вызовов функций GUDF.DLL на встроенные (например, G_B_AND => BIN_AND).

Алгоритм

Перед началом работы

  1. Проверяем наличие, комплектность и работоспособность встроенного сервера Firebird 2.5. Если нет, то сообщаем пользователю о необходимости переустановки программы и выходим.

Если на вход передано имя файла бэкапа базы данных

  1. Пытаемся восстановить из бэкапа базу данных применяя в указанной последовательности сервера: Yaffil, FB 1.5, FB 2.0, FB 2.1, FB 2.5.
    1. Если удалось восстановить БД, то выполняем алгоритм "Если на вход передано имя файла базы данных".
    2. Если не удалось восстановить, то сообщаем об ошибке.

Если на вход передано имя файла базы данных

  1. Подключаемся к БД с помощью ФБ 2.5 и определяем версию структуры БД.
  2. Отключаемся от базы.
  3. Если уже 2.5, то спрашиваем пользователя стоит ли продолжать?
    1. Пользователь может выбрать конвертацию базы FB 2.5, например, если ему надо заменить внешние функции на встроенные.
  4. В зависимости от определенной версии структуры БД проверяем наличие, комплектность и работоспособность встроенного сервера Firebird или Yaffil нужной нам версии.
    1. Если нет, то сообщаем пользователю о необходимости переустановки программы и выходим.
  5. Выводим пользователю подробную информацию о том, что мы будем сейчас делать:
    1. Полное имя исходной базы данных.
    2. Версия исходной базы данных.
    3. Версия исходного сервера.
    4. Версия нового сервера.
    5. Полное имя архивного файла. Поле доступно для редактирования. Например, пользователь может разместить файл на другом диске.
    6. Полное имя временной базы данных. Поле доступно для редактирования. Например, пользователь может разместить файл на другом диске.
    7. Логин и пароль для запуска утилиты gfix, gbak??
    8. Размер страницы новой базы данных и размер кэша в страницах. Пользователь может изменять значения. Если нам удастся получить значения из существующей базы, то выводим их в качестве значений по-умолчанию.
    9. Кодовая таблица для конвертации новой базы данных. Пользователь может выбрать значение из списка. Если нам удастся получить значение из существующей базы, то выводим его в качестве значения по-умолчанию.
    10. Список функций для замены. Пользователь может редактировать список.
  6. Если пользователь ознакомился со списком и нажал кнопку Конвертировать, то продолжаем.
  7. Определяем (приблизительно) потребность в дисковом пространстве для конвертации БД. Используем формулу: Размер БД * 1.5 (Учитываем пространство на копию БД + архив БД).
    1. Если недостаточно -- информируем пользователя. На этом шаге пользователь имеет возможность освободить место на диске и повторить проверку. Если места все равно недостаточно, то возвращаемся к предыдущему экрану, где пользователь может указать иное размещение файла с архивом.
  8. Создаем копию файла БД на которой будем выполнять преобразование. Если файл с таким именем уже существует, то спрашиваем пользователя о перезаписи.
  9. Вызываем через сервис проверку БД с ключами -full -mend для устранения возможных ошибок в структуре.
  10. Подключаемся сервером, соответствующим версии структуры БД.
  11. Составляем список внешних функций для которых есть зависимые объекты. Удаляем из списка функции, которые мы будем менять на встроенные в процессе конвертации. Для оставшихся определяем необходимые сторонние библиотеки и проверяем их наличие.
    1. Если нужной библиотеки нет в соответствующем подкаталоге со встроенным сервером, то сообщаем пользователю. Пользователь должен скопировать библиотеку из рабочего каталога своего сервера. После этого сканирование списка функций повторяется.
      1. Если пользователь не может найти и скопировать нужную библиотеку, то сообщаем и останавливаем процесс конвертации.
  12. Создаем временные таблицы, куда в порядке зависимости скидываем коды:
    1. триггеров (Так как в последствии мы не удаляем тело триггера, а только комментируем его, то нет смысла скидывать полный код. Достаточно запомнить имя триггера, чтобы в последствии знать что восстанавливать.),
    2. процедур (аналогично как и для триггера, см. выше),
    3. представлений,
    4. вычисляемых полей.
  13. Тела триггеров делаем закомментированным. Используем комментарий со специальной сигнатурой, чтобы корректно удалить его в будущем.
  14. Тела процедур делаем закомментированным. Используем комментарий со специальной сигнатурой, чтобы корректно удалить его в будущем.
  15. Представления удаляем.
  16. Вычисляемые поля удаляем.
  17. Удаляем из списка внешних функций все функции, которые теперь являются встроенными в сервер.
  18. Делаем бэкап базы (через сервис).
  19. Отключаемся от базы.
  20. Восстанавливаем базу из архива поверх сделанной копии с ключами -REP -FIX_FSS_DATA -FIX_FSS_METADATA, используя утилиту gbak[1] из комплекта сервера Firebird 2.5.
  21. Загружаем локальный ФБ 2.5.
  22. Воссоздаем вычисляемые поля.
  23. Воссоздаем представления в порядке зависимости.
  24. Восстанавливаем процедуры в порядке зависимости.
  25. Восстанавливаем триггеры.
  26. Удаляем промежуточный архивный файл.
  27. Переименовываем старый файл базы данных в *.BAK.
  28. Переименовываем преобразованный файл базы данных.
  29. Сообщаем пользователю. Завершаем процесс.

Обработка исходного кода вычисляемых полей, представлений, триггеров и процедур при восстановлении

В соответствии с заданным списком корректируем исходный код. Например, в списке задана замена:

 GS_B_AND => BIN_AND
 LENGTH   => CHAR_LENGTH

Мы будем искать в исходном коде все вызовы функций GS_B_AND и LENGTH и заменять их на BIN_AND и CHAR_LENGTH соответственно.

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

Сам список замены предлагается хранить в файле substitute.ini. Имя параметра -- это имя исходной функции, а значение -- новой, на которую меняем. Для доступа к файлу будем использовать функции WinAPI. Пример файла:

 GS_B_AND = BIN_AND
 GS_B_OR  = BIN_OR
 LENGTH   = CHAR_LENGTH
 ...

Обработка ошибок при восстановлении

Если при восстановлении триггера/процедуры возникает ошибка, например из-за того, что программный код использовал особенности сервера Yaffil, которые не поддерживаются сервером Firebird 2.5, то сообщаем об этом пользователю и предлагаем два варианта:

  1. Прервать процесс обновления.
  2. Восстановить процедуру/триггер c закоментированным телом.
  3. Открыть текст процедуры/триггера на экране для того, чтобы пользователь мог внести в него исправления.

Если пользователь выбрал первое, то завершаем процесс и удаляем все временные файлы. Если второе -- по окончании процесса сообщаем ему список процедур/триггеров, которые необходимо исправить вручную.

Если при воссоздании вычисляемого поля или представления возникает ошибка, например из-за того, что программный код использовал особенности сервера Yaffil, которые не поддерживаются сервером Firebird 2.5, то сообщаем об этом пользователю и предлагаем:

  1. Прервать процесс обновления.
  2. Открыть текст поля/представления на экране для того, чтобы пользователь мог внести в него исправления.

Если пользователь выбрал прервать, не забываем удалиь все временные данные с диска.

Особенности реализации

Имя проекта

FDBCONVERT -- Converter of Firebird database files.

Разделение кода и интерфейса

Учитывая что мы предусматриваем два режима работы: из командной строки и интерактивно, ни в коем случае код не должен быть перемешан с интерфейсом.

Многопоточная архитектура

Чтобы не "замораживать" интерфейс пользователя на время выполнения длительных операций бэкапа/разбэкапа следует вынести их в отдельные нити.

Организация пользовательского интерфейса

Предлагается организовать интерфейс ввиде многостраничного пошагового мастера. Предположительное содержание страниц:

  1. Приветствие, выбор языка интерфейса.
  2. Выбор файла базы данных или файла архива для конвертации.
  3. Вывод подробной информации:
    • исходный файл, его версия,
    • конечный файл,
    • исходная версия сервера,
    • конечная версия сервера,
    • место на диске,
    • новый размер страницы,
    • новый размер кэша,
    • кодовая таблица символов.
  4. Вывод списка замены функций. Пользователь может удалять из списка функции, тогда они останутся в базе как есть сейчас.
  5. Вывод информации перед самым стартом. Ничего менять нельзя.
  6. Ход процесса.
  7. Завершение:
    1. Успешное. Объясняем пользователю где находится его новая база и где переименованный файл старой базы.
    2. Не успешное. Показываем лог ошибок. Объясняем, что его старая база осталась нетронутой. На всякий случай выводим где она находится.
  8. Страница с рекламой (и автоматическое открытие в браузере нашего сайта).

Структура метаданных

Это черновик!

 CREATE TABLE CNV$DATA (
   id             INTEGER NOT NULL PRIMARY KEY,
   obj_type       CHAR(1) NOT NULL,
   name           VARCHAR(60) NOT NULL CHARACTER SET UNICODE_FSS,
   relation_name  VARCHAR(60) CHARACTER SET UNICODE_FSS,
   source         BLOB SUB_TYPE 1 CHARACTER SET UNICODE_FSS,
   CHECK(obj_type IN ('T', 'P', 'F', V'))  
 )

Для заполнения поля ID создадим генератор:

 CREATE GENERATOR CNV$G_ID

и триггер:

 CREATE TRIGGER CNV$BI_DATA FOR CNV$DATA
   BEFORE INSERT
   POSITION 0
 AS BEGIN
   NEW.id = GEN_ID(CNV$G_ID, 1);
 END 

Мультиязычная поддержка

Мультиязычная поддержка будет реализована следующим образом:

  1. В подкаталоге AppName (см. ниже структуру каталогов) будет располагаться файл languages.ini.
    1. Каждая секция файла содержит перевод экранных элементов для одного языка.
    2. Название секции -- название языка.
    3. Имя параметра -- это имя контрола или имя некоторого свойства.
    4. Значение параметра -- это метка (заголовок) на языке секции.
  2. Для доступа к содержимому файла мы будем использовать функции WinAPI.
  3. На первом экране программы (см. организацию пользовательского интерфейса) присутствует выпадающий список с названиями доступных языков. Список заполняется при старте программы, в результате сканирования файла languages.ini.
  4. При смене языка, метки (заголовки) экранных элементов заменяются значениями, прочитанными из файла languages.ini.

Пример содержимого файла languages.ini:

 ...
 [English]
 lblBkFile=Backup filename
 lblSourceDB=Source database
 ...

 [Russian]
 lblBkFile=Файл архива
 lblSourceDB=Исходная база данных
 ...

Структура каталогов программы

В соответствии со спецификацией Portable Apps:

 AppNamePortable
 + App
   + AppInfo
   + AppName
     + YA887
     + FB103
     + FB155
     + FB205
     + FB250
   + DefaultData
 + Data
 + Other
   + Help
   + Images
 + Source

Примечания

  1. Мы используем автономную утилиту вместо обращения к сервисам, так как последние не поддерживают упомянутые ключи.
Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты