Aprenda PL/SQL

report_error2

Este é mais um daqueles casos que temos que chamar o Padre Quevedo pra dizer: “Este fenômeno nôm exziste“. Abaixo, vamos fazer uma análise de um programa com erro e como foi solucionado o erro.

O PROBLEMA

O relatório funcionava perfeitamente. Mas raramente, ou seja, 1% das vezes em que era executado, o relatório saía com os valores de todos os campos duplicados! Exemplo:  Deveria sair o valor R$ 20,00  mas saía R$ 40,00. Isso ocorria em todas colunas!

FUNCIONAMENTO DO RELATÓRIO

O usuário informa os parâmetros em uma sessão do Oracle Forms. (Concorrente do Oracle EBS)
O relatório é gerado por uma procedure em uma outra sessão, e insere as linhas em uma tabela comum do Oracle.
Nesta tabela existe um campo chamado SESSAO onde é gravado o SESSION_ID que é passado via parâmetro. (A mesma sessão do Oracle Forms). Dessa forma, vários usuários podem executar o relatório ao mesmo tempo que o programa sempre filtra pela sessão, assim cada um só vê o que é seu, pois cada usuário está numa sessão diferente do Forms.

Ou seja, após disparar o relatório, a procedure é executada em background (é disparado um concorrente do Oracle EBS, que é basicamente, uma sessão do banco executando o programa).

O programa funcionava basicamente em 4 etapas:

1. A procedure limpa a tabela onde os dados serão inseridos e dá um COMMIT. Basicamente, roda um

DELETE FROM tabela WHERE SESSAO=p_sessao;
COMMIT;

2. Procedure roda diversos cursores inserindo nessa tabela. (cada cursor demora +ou- um minuto).
É gravado nessa tabela o número da sessão corrente do Oracle passada via parâmetro.
3. COMMIT;
4. É disparado uma outra sessão (XML Publisher) que monta o relatório com base nos valores inseridos.
Novamente, é passado o número SESSION_ID via parâmetro e o relatório mostra apenas o que é da sessão do usuário que informou os parâmetros.

O que ocorria para dar as linhas duplicadas

O erro ocorria quando o mesmo usuário executava duas vezes o relatório em um curto espaço de tempo.
Dessa forma, o seguinte “fenômeno” era realizado:

EXECUÇÃO 1 EXECUÇÃO 2 Explicação
É executado a limpeza da tabela e realizado Commit. (etapa1) Sem nenhum prolema até agora
Programa começa a executar os cursores e inserir na tabela com o número da sessão X. Este processo leva alguns minutos.
Programa executa a limpeza da tabela, mas não tem nada ainda, pois a outra sessão ainda não fez COMMIT nos dados inseridos! Usuário disparou novamente o relatório, com parâmetros diferentes, mas é a mesma sessão do Oracle Forrms.
COMMIT; A primeira execução comitou.
Programa começa a executar os cursores e inserir na tabela com o número da sessão X. Aqui ocorre a duplicidade
Dispara a execução do Relatório. Relatório sai corretamente.
COMMIT;
Dispara a execução do Relatório. Essa execução vinha com dados duplicados!

É interessante notar que caso o usuário rodasse o relatório em um periodo de tempo um pouco maior, ou seja, após o segundo COMMIT da primeira execução, o erro não aconteceria, pois o DELETE da segunda execução ia conseguir ver os dados inseridos na primeira execução e limpá-los corretamente.

Correção do problema

Após descoberto o que ocorria realmente, foi muito fácil solucionar o problema, pois em vez de se usar o número da sessão apenas, foi também concatenado a esse número outro número que não iria se repetir. Dessa forma, mesmo que o usuário executasse duas vezes o relatório, o número da sessão seria único e o problema não ocorreria.

Este é um exemplo real de bug encontrado em programa, que foi difícil achar o problema devido a raridade que o erro ocorria.

Comments are closed.