Триггеры для конвертации |
Триггеры для конвертации - особый тип триггеров. Он устанавливается на площадке пользователя при поставке новой версии. В момент конвертации у пользователя в БД присутствуют 2 копии таблиц, структура которых была изменена: старая копия, и новая копия. Доступ к данным старой БД возможен в полном объеме, т.е. можно написать отдельный объект, который произвольно обрабатывает данные в старом формате. К новым данным доступ возможен только через специфические функции, описанные ниже. Стоит так же учитывать, что таблицы, структура которых не изменялась, не конвертируются, и доступ к ним через указанные функции невозможен.
Соответственно, при подготовке конвертера триггеры следует откомпилировать на старой БД. А для новой БД, воспользоваться утилитой tbl2obj, которая в том числе умеет генерировать include-файл со структурой буфера новой таблицы.
Триггеры для конвертации являются обычными триггерами. Особенностью является то, что эти триггеры бывают только типа after, и не откатываются.
Важной особенностью является то, что триггеры для конвертации будут работать только с таблицами, имеющими хотя бы один уникальный ключ (индекс). В случае наличия суррогатного ключа (nRec) используется он, в противном случае используется самый короткий из уникальных ключей. Записи в старой и новой таблицах будут идентифицироваться по этому ключу. Если запись с таким ключем не существует, то будет создана новая, в противном случае будет изменена существующая.
В триггерах на конвертацию можно использовать те же функции, что и в обычных триггерах:
А так же дополнительные функции:
Важной особенностью является то, что пользователь может изменить таблицы данных, добавив туда свои поля. Значения этих полей копируются только в функции ModifyTableRecord. Значит, поменяв код и имя таблицы мы потеряем значения пользовательских полей. Отсюда следует существенная разница в использовании функций ModifyTableReord и ModifyAnyTableReord. Первая копирует пользовательские поля, вторая нет.
Пусть у нас есть таблица
create table aaa1 component aaa with table_code = 2001 with tableOptions header ( s : string[40], w : word, l : lvar ) with index ( byS = s(unique) );
и в следующей версии мы из нее сделали такую
create table aaa1 component aaa with table_code = 2001 with tableOptions header ( s : string[40], x : string[5], l : lvar ) with index ( byS = s(unique) );
тогда триггер для конвертации может выглядеть следующим образом
#include recAaa1.inc handler with replace c_aaa1 on trigger aaa1 convert action { var old_buf: record as table aaa1; // буфер старой таблицы var new_buf: recAAA1; // буфер новой таблицы, берем из include-файла GetTableBuffer(old_buf); // считываем старый буфер new_buf := recAAA1(old_buf); // копируем не изменившиеся поля new_buf.x := '['+string(old_buf.w)+']'; // и модифицированное поле SetTableMemo(GetTableMemo); // копируем мемо-поле ModifyTableRecord(new_buf); // сохраняем изменения result := true; }
Если мы хотим внести изменения в мемо поле, то это можно сделать, например, так:
// можно написать вместо строчек // SetTableMemo(GetTableMemo); // ModifyTableRecord(new_buf); var f, ff: longInt; var s, n: string; f := OpenFileHandle(GetTableMemo); // открываем поток с мемо-полем ff := CreateFileHandle('xxx'); // создаем хендл с именем ххх n := CreateTmpFileName; file_openFile(n, stCreate, ff); // открываем файл для нового мемо-поля file_readln(s, f); // читеам старое s := '['+s+']'; // как-то обрабатываем file_writeln(s, ff); // записываем в файл SetTableMemo(GetMemoHandleFF(ff)); // сохраняем изменения как мемо-поле // реальное копирование мемо-поля из файла происходит в этой функции // поэтому закрывать хендлы нужно после нее ModifyTableRecord(new_buf); DeleteFileHandle(f); // закрываем хендл DeleteFileHandle(ff); // закрываем хендл
Реальное копирование мемо-поля из файла происходит в функции ModifyTableRecord, поэтому закрывать хендлы c файлами нужно после ее вызова.
Атлантис 5.1.10.