Использовать триггеры Sybase для записи динамического оператора, используя все старые и новые значения для создания собственного журнала операторов транзакции репликации? - PullRequest
0 голосов
/ 05 апреля 2019

РЕЗЮМЕ ЗАДАЧИ

Я должен написать триггеры генерации операторов I / U / D для самодельной системы двунаправленной репликации в стиле Bucardo / симметричногоDS между группами узлов Sybase ADS и Postgresql 11, используя триггеры BEFORE на любых Postgresql и Sybase DB, которые создают Команды вставки / обновления / удаления на основе команды, введенной в реплицирующую исходную таблицу: например, INSERT INTO PERSON (first_name,last_name,gender,age,ethnicity) Values ('John','Doe','M',42,'C') и манипулировать ими в соответствующем операторе Insert и UPDATE, получая значения OLD и NEW для динамического создания оператора UPDATE, а также значения OLD для создания команды DELETE, которые все запускаются для каждой команды в пункте назначения через некоторый интервал ,

Я знаю, что это сложно, и никто не делает этого, но это для работы, и у меня нет других вариантов, и я не могу возразить, чтобы предложить другое решение. У меня нет других товарищей по команде или человеческих ресурсов, которые могли бы помочь вне SO, и что-то вроде Codementors, что было не так полезно. Моя идея / стратегия состоит в том, чтобы копировать части bucardo / SymmetricDS при вставке значений OLD и NEW для генерации оператора / команды для выполнения в месте назначения. Прямо сейчас я делаю снимок всей таблицы в CSV, в отличие от выполнения отдельной командой, но с помощью команды и циклического перемещения по таблице, которая генерирует и сохраняет команды, сделает работу намного проще.

Одна большая проблема заключается в том, что они приходят из Sybase ADS и имеют смешанную структуру Key / Index (многие таблицы не имеют PK) и отражают это в Postgresql, поэтому я пытаюсь написать операторы без PK или все столбцы команды, чтобы обойти таблицы no-pk. Они также будут реплицировать только определенные столбцы для определенных таблиц, поэтому у меня есть столбец в таблице для вставки имен столбцов, разделенных символом ';' а затем разбить его на массив и связать имена столбцов со значениями для каждого оператора, чтобы сгенерировать полную команду для I / U / D, надеюсь. Я открыт для других стратегий, но это большой сольный проект, и я с большим трудом справился с ним.

В основном я из ДБА и имею некоторый опыт программирования с основами, поэтому я в основном псевдокодирую каждую основную последовательность, ищу синтаксис по частям и настраиваюсь по мере появления или сталкиваюсь с неспособностью языка. Я благодарен за любую помощь, оказанную, поскольку я становлюсь немного отчаянным и обескураженным.

ЧТО Я ПОПЫТАЛ

Я должен сделать это для Sybase ADS и Postgresql, но этот вопрос по сути вопрос ADS, поскольку он более сложный и старый.

Наличие одной таблицы «Журнал», которая отслеживает изменения строк для каждой из реплицируемых таблиц и записей и в конечном итоге динамически генерирует команду, является целью для обеих платформ. Я пытаюсь сделать триггер заявления вроде:

CREATE TRIGGER PERSON_INSERT
ON PERSON
BEFORE 
INSERT
BEGIN
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'INSERT','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
END;

CREATE TRIGGER PERSON_UPDATE
   ON PERSON
   BEFORE 
   UPDATE 
BEGIN 
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'U','UPDATE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
UPDATE Backlog SET OldValues=select ''first_name';'last_name';'gender';'age';'ethnicity'' from __old where SourceTableID=select ID from __old;
END;

CREATE TRIGGER PERSON_DELETE
   ON PERSON
   BEFORE 
   DELETE 
BEGIN 
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, OldValues) select ID, 'D','DELETE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __old;
END;

но я бы хотел, чтобы "'' first_name ';" last_name ";" пол ";" возраст ";" этническая принадлежность "" "пришли из другой таблицы в качестве значения, чтобы сделать его динамическим, поскольку несколько таблиц будут записывать свое значение и информация выписки в единую таблицу журнала. Затем его можно преобразовать в переменную, а затем, вероятно, разделить, чтобы связать с соответствующими значениями, чтобы можно было создавать операторы IUD, которые будут выполняться по месту назначения по одному.

ПОПЫТКА НЕПОЛНОГО ОБРАЗЕЦ КОДА ТРИГГЕРА

CREATE TRIGGER PERSON_INSERT
   ON PERSON
   BEFORE 
INSERT
BEGIN
--Declare @Columns string
--@Columns=select Columns from metatable where tablename='PERSON'
--String Split(@Columns,';') into array to correspond to new and old VALUES
--@NewValues=@['@Columns='+NEW.@Columns+'']
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'INSERT','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
END;

CREATE TRIGGER PERSON_UPDATE
   ON PERSON
   BEFORE 
   UPDATE 
BEGIN 
--Declare @Columns string
--@Columns=select Columns from metatable where tablename='PERSON'
--String Split(@Columns,';') into array to correspond to new and old VALUES
--@NewValues=@['@Columns='+NEW.@Columns+'']
--@OldValues=@['@Columns='+OLD.@Columns+'']
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'U','UPDATE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
UPDATE Backlog SET OldValues=select ''first_name';'last_name';'gender';'age';'ethnicity'' from __old where SourceTableID=select ID from __old;
END;

CREATE TRIGGER PERSON_DELETE
   ON PERSON
   BEFORE 
   DELETE 
BEGIN 
--Declare @Columns string
--@Columns=select Columns from metatable where tablename='PERSON'
--String Split(@Columns,',') into array to correspond to new and old VALUES
--@OldValues=@['@Columns='+OLD.@Columns+'']
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, OldValues) select ID, 'D','DELETE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __old;
END;

ЗАКЛЮЧЕНИЕ

Для каждой вставленной, обновленной или удаленной строки; в столбце COMMAND в таблице журнала я пытаюсь сгенерировать соответствующий оператор типа INSERT INTO PERSON ('+ @ Columns +') VALUES ('+ @ NewValues ​​+') 'или UPDATE или DELETE. Затем служба Foreach будет выполнять каждое значение команды, упорядоченное по времени создания, в качестве основной службы репликации.

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

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

1 Ответ

0 голосов
/ 21 апреля 2019

Это сложная, но решаемая проблема, для написания которой потребуется время и тщательное планирование.Я думаю, что вы ищете команду «Execute Immediate» в синтаксисе ADS SQL.С помощью этой команды вы можете создать динамический оператор, который будет выполняться после завершения построения оператора SQL.Сохраните каждое желаемое значение столбца во временной таблице, осторожно составив оператор в виде строки, а затем выполните его с помощью Execute Immediate.Например:

DECLARE TableColumns Cursor ; 
DECLARE FldName Char(100) ;
...
OPEN TableColumns AS SELECT * 
                       FROM system.columns 
                      WHERE parent = @cTableName 
                        AND field_type < 21 //ADS_ROWVERSION
                        AND field_type <> 6 //ADS_BINARY 
                        AND field_type <> 7; //ADS_IMAGE

While Fetch TableColumns DO

    FldName = Trim( TableColumns.Name) ;

    StrSql = 'SELECT New.[' + Trim( FldName ) + '] newVal' +
             'INTO #myTmpTable FROM ___New n' ;

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

EXECUTE IMMEDIATE STRSQL ; 

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

Кроме того, я думаю, что вы можете создать функцию для DD, которая будет фактически вызываться из каждого триггера в таблицах, которые вы хотите отслеживать, вместо того, чтобы писать длинный триггер для каждой таблицы, и cTableName может бытьПараметр отправлен в функцию.Это сделало бы обслуживание немного легче.

...