Mistério no RDBMS Oracle – Mês não reconhecido
Recentemente, um colega encontrou a seguinte situação ao fazer um import a partir de um dump file fornecido pelo cliente dele:
Import: 64bit Production
Connected to: Oracle Database xxx Release x.y.z. - 64bit Production
Master table "CHIAPPA"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "CHIAPPA"."SYS_IMPORT_FULL_01": CHIAPPA/******** directory=DATA_PUMP_DIR logfile=TAB_TESTE.impdp dumpfile=TAB_TESTE.DMP
Processing object type TABLE_EXPORT/TABLE/TABLE
ORA-39083: Object type TABLE failed to create with error:
ORA-01843: not a valid month
Como o colega tem alguma experiência, ele já sabia que é comum receber erro do tipo quando você está programando ou inserindo/alterando dados e informa uma string contendo o valor de data – se não for especificado um formato de data, a string é convertida usando defaults, que nem sempre funcionam adequadamente…
O mistério aqui é que ele NÃO estava programando nada, a tabela estava vazia (PORTANTO não havia INSERTs sendo feitos), E outras tabelas no banco também possuíam colunas DATE, que funcionaram ok…De onde vem o erro, então ?
… pausa para suspense ….
A resposta é simples ao extremo : um desenvolvedor não apenas codifica quando escreve um programa PL/SQL ou um programa SQL (com SELECT, INSERT , UPDATE ou DELETE), mas TAMBÉM quando cria um objeto com CREATE há código que é possível anexar ao objeto, como TRIGGERs, VIEWs, OU MESMO (o que era o problema) ao indicar coisas como DEFAULTs… ISSOO TUDO é sim código SQL, criado pelo programador, então as regras de conversão implícita SE APLICAM sim…
No caso, o cliente do meu colega tinha ‘programado’ o DDL dele assim:
SQL>create table TAB_TESTE (c1 number, c2 date default '12-31-2020');
Tabela criada.
Como lá no banco original dele o formato de data default era de MM-DD-YYYY lá o código indicando o DEFAULT fez a conversão implícita certinho… A solução ?? Muito simples, como já dito N+1! vezes aqui no Fórum e em muitos outros sites e fontes de referência, basta em QUALQUER CÓDIGO o desenvolvedor usar conversão EXPLÍCITA, sempre, assim:
SQL>create table TAB_TESTE2 (c1 number, c2 date default (TO_DATE('12-31-2020', 'MM-DD-YYYY')) );
Tabela criada.
Com essa singela correção um novo dump file gerado pôde ser lido e importado ok… Fim do mistério, e fica NOVAMENTE a lição: Em qualquer código, desenvolvido em SQL ou em PL/SQL, conversão de datatype IMPLÍCITA é má, é perigosa, é algo a ser EVITADO….