Skip to content
Guia de programação
para linguagem de banco
Introdução
Padrões Gerais
Estrutura
Exportação para Checkout
Metadados
Views
Functions
Triggers
Packages

Esse artigo reúne os conhecimentos relacionação a criação e manutenção de triggers de banco para o Totali Commerce.

Tutoriais ​

Como criar uma nova trigger ​

1. Criar trigger na pasta ansi\trigger dos fontes do totalicommerce.

Modelos ​

Modelo de trigger para tabela de dados do Commerce [TT_] com filial:
https://dev.azure.com/eme4sistemas/Totall/_git/totallcommerce?path=/modelos/ansi/Criar_Trigger.mac

Modelo de trigger para tabela de dados do Commerce [TT_] sem filial:
https://dev.azure.com/eme4sistemas/Totall/_git/totallcommerce?path=/modelos/ansi/Criar_TriggerTTSemFilial.mac

Modelo de trigger para tabela de domínios do Commerce [TD_]:
https://dev.azure.com/eme4sistemas/Totall/_git/totallcommerce?path=/modelos/ansi/Criar_TriggerTD.mac

Modelo de trigger para tabela de log do Commerce [TL_]:
https://dev.azure.com/eme4sistemas/Totall/_git/totallcommerce?path=/modelos/ansi/Criar_TriggerTL.mac

Modelo de trigger para tabela de importação do Commerce [TI_]:
https://dev.azure.com/eme4sistemas/Totall/_git/totallcommerce?path=/modelos/ansi/Criar_TriggerTI.mac

Modelo de trigger que registra alterações em uma tabela [TT_]:
https://dev.azure.com/eme4sistemas/Totall/_git/totallcommerce?path=/modelos/ansi/Criar_TriggerRegistraLog.mac

Script para gerar comparações de coluna em triggers que registram alterações:
https://dev.azure.com/eme4sistemas/Totall/_git/totallcommerce?path=/modelos/ansi/CRIA_TRIGGER_LOG.sql

Padrões ​

Seguir os padrões gerais definidos em Padrões Gerais para Programação de Banco do Totali Commerce e os específicos definidos neste artigo.

Nomenclatura ​

Usar TG<tipo da tabela, exceto quando for TT><sufixo da tabela><sequenciador, quando tiver mais de uma trigger>:

  • TGIVE1
  • TGIVE2
  • TGIVE3
  • TGIVE4
  • TGLOT
  • TGLPRO

Exceções:
_testenull_tt_pro: Trigger gerada pelo GeraTriggers (disparado pelo compilador) para transformar inserts e updates em branco para nulo. Em PostgreSQL "" é diferente de null. Então quando sistema grava "" transformamos em null para manter compatibilidade com Oracle e também para poder usar IS NULL. A estrutura é baseada na base COMPI da versão que está sendo compilada.

TGTAB_ASS: Registra quantidade de registros assinados em tabelas protegidas para PAF-ECF.

TGTAB_DW: Grava dados resumidos em tabelas auxiliares para o processo de Dashboard.

TG_TI_TAB: Faz Trim em campos VARCHAR de tabelas de importação, para impedir que parceiro manda dados com espaços. Gerada pelo GeraTriggers a partir da base COMPI (PostgreSQL), é gerado tanto para Oracle quanto para PostgreSQL.

TG_LOG_TD_TAB: Registra log das alterações de configuração na tabela TL_CFG. Gerada pelo GeraTriggers a partir da base COMPI (PostgreSQL), é gerado tanto para Oracle quanto para PostgreSQL.

Nome do Arquivo ​

O nome do arquivo deve ser o nome da trigger sem o sequenciador:

  • TGABA.mac
  • TGDICM.mac
  • TGRMOV.mac

Conteúdo do Arquivo ​

No arquivo deve conter todas as triggers de uma tabela. E nada mais.

Prefixos NEW e OLD ​

Devemos usar os prefixos :NEW. e :OLD. em maiúsculo (caixa-alta).

Mensagens de Exceções (raise) ​

Em triggers o raise precisa usar a constante COMPLEMENTO no final da mensagem.

Veja mais sobre Mensagens de Exceção em Guia para Manutenção de Functions e Procedures do Totali Commerce.

Melhores Práticas ​

Triggers para Execução a Cada Linha (FOR EACH ROW) ​

As triggers de execução a cada linha são as mais comuns no sistema. Elas são disparadas a cada linha atualizada por um determinado comando. Criamos elas utilizando as macros BEGINTRIGGER e ENDTRIGGER. Os parâmetros serão explicados a seguir.

%%<BEGINTRIGGER('nome trigger', 'quando', ['lista de eventos'], 'tabela',['campos'])&gt;%% DECLARE -- Objetivo(s): -- 1. Explicar o objetivo 1 aqui... -- 2. Explicar o objetivo 2 aqui...   -- Declaração de variáveis e cursores cVariavelExemplo VARCHAR(20);   -- Principal BEGIN IF INSERTING THEN ... END IF;   IF UPDATING THEN ... END IF;
  IF DELETING THEN ... END IF;
  %%<ENDTRIGGER('nome trigger', 'quando', ['lista de eventos'], 'tabela')&gt;%%

Nome da trigger: Apenas informar nome da trigger.
Quando: Passamos BEFORE (antes) ou AFTER (depois).
Ex.: 'BEFORE' ou 'AFTER'
Lista de Eventos: Passamos as operações como uma lista de strings.
Ex.: ['INSERT','UPDATE'] ou ['INSERT','UPDATE','DELETE'].
Tabela: Passar a tabela cujo alterações dispararão a trigger.
Colunas: Opcionalmente podemos passar colunas também, para que a trigger só seja disparada ao modificar as colunas.

Triggers para Execução a Cada Comando (FOR STATEMENT) ​

As triggers de execução a cada comando são utilizadas para alguns fins específicos no sistema, como por exemplo:

  • controlar array de registros alterados para ser usado em packages.
  • validar limite de registros em um tabela.
  • eliminar registros de tabelas temporárias.

Elas são criadas utilizando as macros BEGINTRIGGER_STAT e ENDTRIGGER_STAT. Os parâmetros são idênticos aos das triggers de linhas.

%%<BEGINTRIGGER_STAT('nome trigger', 'quando', ['lista de eventos'], 'tabela',['campos'])&gt;%% DECLARE -- Objetivo(s): -- 1. Explicar o objetivo 1 aqui... -- 2. Explicar o objetivo 2 aqui...   -- Declaração de variáveis e cursores cVariavelExemplo VARCHAR(20);   -- Principal BEGIN IF INSERTING THEN ... END IF;   IF UPDATING THEN ... END IF;
  IF DELETING THEN ... END IF;
  %%<ENDTRIGGER_STAT('nome trigger', 'quando', ['lista de eventos'], 'tabela')&gt;%%

Precedência ​

A precedência de execução das triggers é a seguinte:

  • BEFORE do tipo STATEMENT
  • BEFORE do tipo FOR EACH ROW
  • AFTER do tipo FOR EACH ROW
  • AFTER do tipo STATEMENT

O Oracle não garante nenhum tipo de ordem de execução em triggers que são do mesmo tipo. Ou seja, se criarmos duas BEFORE do tipo FOR EACH ROW não há garantia nenhuma de que uma executará sempre antes da outra.

Já em PostgreSQL, a execução de triggers do mesmo tipo são definidas pela nome. Por isso, que as triggers de "_teste_null" possuem o underline no início do nome. Isso garante que elas serão executadas antes de qualquer outra trigger BEFORE do tipo FOR EACH ROW.

Operações ​

Podemos definir para que tipo de operação que a trigger será disparada. Podemos diferenciar entre Insert, Update ou Delete. Dentro da trigger, sempre especificar para qual operação estamos programando determinada regra. Podemos verificar a operação consultando as constantes INSERTING, UPDATING e DELETING.

IF INSERTING THEN -- Sempre identificar a operação em que a regra pode ser utilizada END IF;   IF INSERTING OR UPDATING THEN -- Sempre identificar a operação em que a regra pode ser utilizada END IF;

Podemos acessar as colunas do registro alterado utilizando os prefixos ":new." e ":old." nas variáveis. Porém, devemos respeitar a seguinte regra:

Operação :new :old
InsertLeitura e gravaçãoNão pode ser utilizado
UpdateLeitura e gravaçãoLeitura
DeleteNão pode ser utilizadoLeitura

Impedir exclusão de registro ​

O padrão do sistema é impedir exclusão dos registros. A vantagem obtida com isso é facilitar manter log de registros e demais operações que envolvam tabelas pais e filhas.

Esse tratamento é feito da seguinte forma:

IF DELETING THEN %%<RAISE('-20000','Registro não pode ser excluído. %', ['COMPLEMENTO'])&gt;%% END IF;

Registrar exclusão de registro ​

Se o sistema permitir exclusão do registro, e a tabela não for temporária ou de transição de dados, devemos registrar quem excluiu o registro.

cRet VARCHAR(2);   IF DELETING THEN cRet := LogExclusao(TRUE,'TT_TAB', :OLD.CODFIL, :OLD.SEQUEN); END IF;

Nesse caso, fazemos um tratamento para registrar e reintrodução da chave na tabela.

IF INSERTING THEN cRet := LogExclusao(FALSE,'TT_TAB', :NEW.CODFIL, :NEW.SEQUEN); END IF;

Erro de Mutating Table ​

Ainda não disponível.

Comparação de Valores ​

Em caso de comparação de valores devemos garantir que comparações em colunas que aceitam NULL será tratado a comparação com um COALESCE para garantir o valor de comparação.

Exemplo

TGCCC2 Estava sendo comparado o campo ":NEW.COMPLE" com valor "VEM_DE_DEVOLUCAO" sem um COALESCE como o campo aceita NULL em alguns clientes estava apresentando problemas na comparação assim não entrando no condicional. Solução adicionado um "COALESCE(:NEW.COMPLE,'X')" na comparação assim garantindo uma comparação de valores.

Atualizar ATU_EM em Tabelas Pais ​

Em alguns casos, a coluna ATU_EM não está na própria tabela, então não podemos fazer uma atribuição simples na variável :NEW.ATU_EM.
Neste caso, temos duas soluções distintas.

Configurações que atualizam ATU_EM em tabelas pais

Na trigger AFTER:

DECLARE cRetorno VARCHAR2(2); BEGIN cRetorno := INSERE_MATU('TT_CPM', 'TT_PRE', cWhere);

Neste exemplo, ao mudar uma Promoção, sistema altera ATU_EM do Preço.

Configurações que atualizam ATU_EM na TT_CFG

Especialmente para o Totali POS, nós criamos a TT_ATU para guardar a data da última configuração, levando em consideração as configurações utilizadas na carga para este sistema.
Só devemos atualizar esta data em triggers de configurações utilizadas na carga do Totali POS.

Na trigger AFTER:

DECLARE cRetorno VARCHAR2(2); BEGIN cRetorno := AtualizaData('CONFIGURACAO',Agora());

Neste exemplo, ao fazer qualquer operação na tabela um registro é incluído na TT_ATU.
A informação de quando alguma configuração foi alterada no sistema deve ser obtida desta tabela.

Categorias ​