Sabe aqueles erros esquisitos onde você olha o código é pensa: “não é possível, tá tudo certo…”?
O cenário
Há muito tempo, trabalhei na migração de diversas procedures de um sistema financeiro de SQL Server para Oracle. Eram procedure complexas com milhares de linhas, muitos cursores e algumas péssimas práticas.
A princípio, a ordem era para migrarmos tudo manualmente. Mas, depois de analisar algumas ferramentas de migração automática, descobri que se fizesse alguns ajustes nas procedures em SQL Server poderia migrá-las inteiramente para Oracle usando o SQL Developer, disponibilizado gratuitamente pela Oracle.
Ao migrar uma procedure, o SQL Developer utiliza algumas rotinas de adaptação para o Oracle, que deve estar disponível num package chamado qlserver_utilites. Fiz um parser simples que substituía as chamadas a esse package por funções nativas do Oracle, evitando criar código desnecessário e que diminuiria a performance.
Escrevi um documento com os ajustes necessários e se tornou o padrão do projeto. Assim conseguimos manter o código-fonte único.
Entretanto, identificamos que algumas operações específicas do sistema geraram lançamentos com valores estranhos, mas a maioria estava correta. No caso, o cálculo envolvia períodos de datas e a primeira observação é que a data inicial do período era dia 30, o último do mês.
Cálculos daqui, cálculos dali, verificou-se que, apenas para esse tipo de período, a procedure estava calculando um dia a mais numa diferença entre as datas. Uma dessas datas era calculada somando-se um número X de meses.
A origem do problema
No Oracle, a rotina usada para somar datas é ADD_MONTHS. Seria o equivalente de DATEADD do SQL Server.
Entretanto, essa rotina segue um padrão ANSI muito esquisito: se a data é o último dia do mês, ao somar X meses, o resultado será sempre no último dia do mês.
Vamos supor que a data fosse 28/02, ao somar um mês, o resultado seria 31/03, a não ser no ano bissexto. Para 30/04, por exemplo, somando-se um mês, o resultado seria 31/05.
Isso estava gerando a distorção nos cálculos.
Solução
Foi necessário criar uma function para somar meses e que mantivesse o dia fixo, a não ser quando o mês do resultado tinha menos dias do que o mês original.
Conclusões
Não confiar na implementação de uma rotina somente pelo nome, principalmente entre softwares tão diferentes.
No caso de migração, analisar a fundo a equivalência de funções, métodos, classes, etc. Se possível, com testes unitários.