Logical Standby: using triggers to replicate Unsupported Tables

Este artigo reproduz uma implementação muito simples, que é dada de exemplo na documentação da Oracle, para os casos onde temos tabelas não suportadas nativamente pelo SQL Apply, e que precisam de uma intervenção manual para que seus dados sejam replicados. Essa operação consiste basicamente na criação de uma tabela paralela, e as triggers que farão o trabalho de replicação em cada evento de DML na tabela de origem. O exemplo foi extraído DESTE material oficial.

Criando um objeto do tipo TYPE no primary e uma tabela que o utiliza em uma de suas colunas:

[oracle@fornix1 ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 19.0.0.0.0 - Production on Sun Apr 4 04:09:42 2021
Version 19.3.0.0.0
 
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
 
SQL> create or replace type SOE.PERSON as object
(
FIRSTNAME varchar2(50), LASTNAME varchar2(50), BIRTHDATE Date );
/  2    3    4
 
Type created.
 
SQL> create table SOE.PERSONS
(
IDNUMBER varchar2(10) , DEPARTMENT varchar2(50), INFO SOE.PERSON );  2    3
 
Table created.

Criando a “shadow table” no primary que será populada via trigger:

SQL> create table SOE.PERSONS_LOG
(
T_IDNUMBER varchar2(10),
T_DEPARTMENT varchar2(50),
T_FIRSTNAME varchar2(50),
T_LASTNAME varchar2(50),
T_BIRTHDATE Date
);  2    3    4    5    6    7    8
 
Table created.

Criando a trigger no primary que populará a shadow table:

SQL> CONN SOE
Enter password:
Connected.
SQL> SHOW USER;
USER is "SOE"
SQL> create or replace trigger flatten_persons
        after insert on persons for each row
declare
begin
        insert into persons_log
         (t_IdNumber, t_Department, t_FirstName, t_LastName, t_BirthDate)
        values
         (:new.IdNumber, :new.Department,
        :new.Info.FirstName,:new.Info.LastName, :new.Info.BirthDate);
end;
/  2    3    4    5    6    7    8    9   10   11
 
Trigger created.

Criando a trigger no primary que populará a tabela no ambiente standby de destino:

SQL> create or replace trigger reconstruct_persons
        after insert on persons_log for each row
begin
        insert into Persons (IdNumber, Department, Info)
        values (:new.t_IdNumber, :new.t_Department,
        Person(:new.t_FirstName, :new.t_LastName, :new.t_BirthDate));
end;
/  2    3    4    5    6    7    8
 
Trigger created.

Rodando o comando abaixo no primary, deixamos configurado para que a trigger possa ser disparada e alimente o standby:

SQL> exec dbms_ddl.set_trigger_firing_property( trig_owner => 'SOE', trig_name => 'RECONSTRUCT_PERSONS', property => dbms_ddl.apply_server_only, setting => TRUE);
 
PL/SQL procedure successfully completed.

Gerando archives no primary:

SQL> CONN / AS SYSDBA
Connected.
SQL> ALTER SYSTEM SWITCH LOGFILE;
 
System altered.
 
SQL> /
 
System altered.
 
SQL> /
 
System altered.

Confirmando que os objetos foram replicados para o standby database:

[oracle@fornix2 ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 19.0.0.0.0 - Production on Tue Apr 6 04:23:21 2021
Version 19.3.0.0.0
 
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
 
SQL> select count(*) from dba_objects where object_name in ('PERSONS', 'PERSONS_LOG');
 
  COUNT(*)
----------
         2

Para testar a replicação, vamos inserir 1 registro na tabela do primary:

[oracle@fornix1 ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 19.0.0.0.0 - Production on Tue Apr 6 04:25:38 2021
Version 19.3.0.0.0
 
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
 
SQL> insert into SOE.Persons (IdNumber, Department, Info)
values (1, 'Database' ,
SOE.Person('Bruno', 'Silva', trunc(sysdate)));  2    3
 
1 row created.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> ALTER SYSTEM SWITCH LOGFILE;
 
System altered.

No logical standby, a tabela e conteúdo já foram replicados com sucesso:

SQL> select count(*) from SOE.persons;
 
  COUNT(*)
----------
         2

Obs: Este procedimento foi criado pelo senhor Ahmed Baraka (www.ahmedbaraka.com) e foi apenas reproduzido por mim em um laboratório pessoal para fins de aprendizado.

Leave a Comment

Your email address will not be published.