20060720

Bugs persistents

Avui hem solucionat un bug força curiós, es tracta d'un "efecte 2000 atrassat".

Teníem un update en el oracle de producció, que contenia la següent condició al where:


or nvl(fi,sysdate-2392.123) <> to_date(nvl(v_fi, sysdate-2392.123),'DD/MM/YYYY HH24:MI')


Tot havia funcionat bé fins avui, i dic avui perquè, ha cascat exactament avui a les 3 de la matinada...

Si us fixeu en la expressió to_date(nvl(v_fi, sysdate-2392.123),'DD/MM/YYYY HH24:MI') veureu que el resultat de sysdate-2392.123 es un date.

Hàbilment al programar-ho no es va pensar que sysdate-2392,123 faria el canvi de segle avui mateix (o si es va pensar, va tenir molta mala llet)

Així que al retornar un date sysdate-2392,123 retornava sempre per sota del 2000 fins avui, que al fer la transformació implícita a varchar2 i fer el to_date fotia un casque impressionant del pal

"Error ORA-01858: se ha encontrado un carácter no numérico donde se esperaba uno numérico"


Això es degut a que la conversió implícita amb el any 99 no es comporta igual que amb el 00

De fet he comprovat que nomes dona una excepció en el any 00, no en el 99 ni en el 02 per exemple, vegeu les imatges:







Evidentment la expressió correcte és:


or nvl(fi,sysdate-2392.123) <> to_date(nvl(v_fi, to_char(sysdate-2392.123, 'dd/mm/yyyy hh24:mi')),'DD/MM/YYYY HH24:MI')


Això no treu que no tingui pinta de ser un bug d'Oracle...

Tot solucionat, encara que es un bug de més de 4 anys i aquests sempre toquen la moral...

Que hi farem.

2 comentarios:

David Pujol dijo...

Hola Agustí,

no és un bug, només que no es va utilitzar la màscara que tocava i es us vàreu fiar de la variable NLS_DATE_FORMAT (que per defecte és DD-MM-YY).

Prova amb aquesta màscara:

or nvl(fi,sysdate-2392.123) <> to_date(nvl(v_fi, to_char(sysdate-2392.123, 'dd/mm/rrrr hh24:mi')),'DD/MM/rrrr HH24:MI')

O canviat el valor de la variable NLS_DATE_FORMAT:

SQL> alter session set nls_date_format = 'dd-mm-yyyy';

Session altered.

SQL> select to_date(to_char(sysdate-2400) , 'dd-mm-yyyy hh24:mi:ss') from dual;

TO_DATE(TO
----------
18-01-2000

SQL> alter session set nls_date_format = 'dd-mm-rrrr';

Session altered.

SQL> select to_date(to_char(sysdate-2400) , 'dd-mm-yyyy hh24:mi:ss') from dual;

TO_DATE(TO
----------
18-01-2000

o simplement posant la màscara correcte:

SQL> select to_date(to_char(sysdate-2400) , 'dd-mm-rrrr hh24:mi:ss') from dual;

TO_DATE(T
---------
18-JAN-00

SQL> select to_date(to_char(sysdate-2400) , 'dd-mm-rr hh24:mi:ss') from dual;

TO_DATE(T
---------
18-JAN-00

SQL> select to_date(to_char(sysdate-2400) , 'dd-mm-yyyy hh24:mi:ss') from dual;
select to_date(to_char(sysdate-2400) , 'dd-mm-yyyy hh24:mi:ss') from dual
*
ERROR at line 1:
ORA-01858: a non-numeric character was found where a numeric was expected

En resum, de bug res, un error de programació :-).

Salutacions
David Pujol

Agustí Pons dijo...

No, si això ja ho tenia clar, de fet es com ho vem arreglar, però com t'expliques que funcioni pel 2001 i el 2002 i en canvi no funcioni pel 2000 ?

La prova es la seguent:

select to_date(to_char(sysdate-1392), 'dd/mm/yyyy hh24:mi') from dual;

que retorna correctament una data del 2002 i

select to_date(to_char(sysdate-2392), 'dd/mm/yyyy hh24:mi') from dual;

Que fot un casque perquè es una data del 2000 ?

Com t'ho expliques ?

Agusti