KDV, 26.01.2004
Версионность метаданных – это механизм, позволяющий динамически менять структуру таблиц, не затрагивая данные, хранящиеся в этих таблицах.
Из этого определения следует, что никакие другие объекты (триггеры, процедуры и т. п.), кроме таблиц, не имеют "версионности".
Версионность структур таблиц обеспечивается следующим механизмом:
При создании таблицы информация о ней записывается в RDB$RELATIONS и RDB$RELATION_FIELDS, а также в RDB$FORMATS. Если в RDB$RELATION_FIELDS перечислены столбцы таблицы в нормальном виде, то в RDB$FORMATS содержатся данные (в столбце rdb$description), описывающие формат записи в двоичном виде. В этом формате указано, из каких типов столбцов состоит запись на диске, и в какой последовательности эти столбцы идут.
Когда происходит вставка записи, сервер сохраняет информацию на диск в соответствии с указанным форматом. Также в заголовок записи записывается номер этого формата (число из rdb$format).
Если произвести операцию изменения структуры таблицы – удалить столбец, добавить столбец, модифицировать тип столбца и т. п., то эти изменения отражаются в rdb$relation_fields, а в таблицу RDB$FORMATS добавляется новая запись, которая содержит номер таблицы, новое описание структуры записи, и новый (очередной) номер формата. Например, при создании таблицы номер формата всегда 1, при следующем изменении – 2, и так далее.
Таким образом, после модификации структуры таблицы сервер знает, каким был предыдущий формат записей. То есть, при чтении записи из ее заголовка извлекается номер формата, далее поля записи читаются в соответствии с этим форматом, после чего запись приводится к виду самого последнего формата данной таблицы.
Основная проблема здесь – это невозможность привести старый формат записи к новому. Возникает она только если изменился тип столбца, и хранимые в старом формате данные не могут быть преобразованы к новому формату. Например, строковый столбец, содержащий буквы, после изменения на целочисленный тип будет выдавать ошибку при попытке чтения данных (подробнее см.
документ).
Поэтому, если добавлять или удалять столбцы, а также менять их местами, можно совершенно безболезненно, то к изменению типа столбца надо отнестись осторожно. И всегда проверять возможность конвертации данных из старого формата в новый. Например, есть некий столбец FIELD, у которого надо сменить тип на INTEGER. Делаем проверку:
SELECT CAST(FIELD as INTEGER) FROM X
причем нужно просмотреть все записи (буквально, жать PgDn в гриде до конца выборки). Если ошибок с преобразованием данных нет, то можно смело выполнить
ALTER TABLE X ALTER FIELD TYPE INTEGER
При ALTER TABLE номер формата всегда только увеличивается. Это означает, что если мы "по ошибке" удалили столбец, и затем хотим его восстановить, то в этом случае все равно в rdb$formats будет храниться как минимум три записи – исходный формат, формат с удаленным столбцом, формат с добавленным столбцом. А записи, если таковые были в таблице, будут иметь номер формата 1. И последовательное наложение форматов один на другой приведет к "исчезновению" данных удаленного столбца.
Исправить ошибку с удалением столбца можно, если скорректировать информацию о формате в системных таблицах (удалить последний формат в RDB$FORMATS и изменить номер формата таблицы в RDB$RELATIONS на предыдущий), однако делать это нужно очень осторожно, попробовав сначала на копии базы данных.
То же самое (увеличение номера формата) относится и к модификации столбца. Т. е. при ошибке конвертации данных в новый тип столбца убрать ошибку путем alter table alter field в старый тип нельзя.
Количество форматов для одной таблицы ограничено на уровне 255, т. е. в заголовке записи под номер формата отводится один байт. Во всех версиях InterBase до версии 6 включительно, увеличение формата происходило и при операции ALTER TRIGGER. Это ошибочное поведение было исправлено в Yaffil и Firebird. Т. е. сейчас увеличение номера формата происходит только при изменении структуры таблицы.
Сбросить счетчик формата можно только при помощи backup/restore. В файл backup пишутся данные в соответствии с самым последним номером формата, и соответственно, никакой перечень форматов не хранится. При restore формат таблицы и данных будет иметь номер 1.
Для проверки на текущий максимальный номер формата можно использовать
запрос.