Триггеры для конвертации Назад В начало Вперед

Триггеры для конвертации - особый тип триггеров. Он устанавливается на площадке пользователя при поставке новой версии. В момент конвертации у пользователя в БД присутствуют 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.