viernes, noviembre 08, 2013

El año 0 y Oracle GoldenGate

El año 0 no existe. Del año -1 (es decir, año 1 antes de Cristo) se pasa al año 1 y el primer año bisiesto de la historia es el año 4.

No obstante, en una base de datos he visto filas que en un campo de tipo DATE habían conseguido introducir una fecha '29-FEB-0000'.

Oracle realiza dos controles con las fechas:

Uno específicamente sobre el año cero, que es el siguiente:

SQL> create table fechas (fecha date);

Tabla creada.

SQL> insert into fechas values (to_date('01-01-0000','DD-MM-YYYY'));
insert into fechas values (to_date('01-01-0000','DD-MM-YYYY'))
                                    *
ERROR en línea 1:
ORA-01841: el valor (completo) del año debe estar entre -4713 y +9999, y no debe ser igual a 0


Otro sobre la validez de la fecha, de modo que:

  • Un día 31 es válido sólo para los meses enero, marzo, mayo, julio, agosto, octubre y diciembre.
  • Un día 29 sólo es válido para el mes de febrero en los años bisiestos.
  • Un día 30 es válido para todos los meses excepto febrero.


SQL> insert into fechas values (to_date('29-02-0001','DD-MM-YYYY'));
insert into fechas values (to_date('29-02-0001','DD-MM-YYYY'))
                                    *
ERROR en línea 1:
ORA-01839: fecha incorrecta para el mes especificado


Como comento en este caso, en una base de datos consiguieron saltar los controles del motor y se introdujeron fechas en año 0, incluso el '29-FEB-0000'.

NOTA: Ni idea cómo lo consiguieron. Intenté insertar esa fecha con SQL dinámico, o desde PL/SQL, etc y siempre recibía alguno de estos dos errores.

SQL>  select CODIGO, FECHA from  TABLA_BASE
  2  where FECHA =(select min(FECHA) from TABLA_BASE);

CODIGO       FECHA
------------ --------------------
000600211048 01-ENE-0000 00:00:00
00060164681- 01-ENE-0000 00:00:00


El caso es que esa base de datos se iba a migrar de Oracle9i a Oracle11gR2, y los procedimientos de export/import propagaban las fechas incluyendo estos registros sobre el año 0. De modo que la importación fue bien, pero en cuanto volvieron a insertar un año 0 en la tabla, al propagarse por Orace GoldenGate al futuro entorno, el error ORA-01841 apareció de pronto.

Oracle GoldenGate Delivery for Oracle process started, group REPL discard file opened: 2013-09-26 17:07:02

Current time: 2013-09-26 17:16:35
Discarded record from action ABEND on error 1841

OCI Error ORA-01841: el valor (completo) del año debe estar entre -4713 y +9999, y no debe ser igual a 0 (status = 1841). UPDATE "APP_OWNER"."TABLA_BASE" SET "ACTIVO" = :a4,"TIPO" = :a5,"DURACION" = :a6,"FECHA" = :a7 WHERE "CODIGO" = :b0 AND "FECHA_ORIGEN" = :b1 AND "CATEGORIA" = :b2 AND "TABLA_BASE_CAT" = :b3

Aborting transaction on ./dirdat/ab beginning at seqno 58 rba 4270475
                         error at seqno 58 rba 4270475
Problem replicating APP_OWNER.TABLA_BASE to APP_OWNER.TABLA_BASE
Mapping problem with compressed update record (target format)...
*
CODIGO = 000600371922
FECHA_ORIGEN = 2004-05-27 00:00:00
CATEGORIA = asi1
TABLA_BASE_CAT = ~#
ACTIVO = NULL
TIPO = T
DURACION = 60
FECHA = 0000-02-29 00:00:00
*

Process Abending : 2013-09-26 17:16:35


Para solucionar esto, en el fichero de parámetros de REPLICAT, hay que mapear las fechas a una fecha válida. Para evitar, además, el problema del 29 de febrero envié el mapeo al año 0004.

Replicat repl
UserID oggadm1@bbdd, password *****
AssumeTargetDefs
DiscardFile ./dirrpt/repl.dsc
ALLOWNOOPUPDATES
TABLEEXCLUDE APP_OWNER.VM_TABLE1_DS
TABLEEXCLUDE APP_OWNER.VM_TABLE2_DS
Map app_owner.tabla_base, Target app_owner.tabla_base,
COLMAP (USEDEFAULTS,fecha=@STRSUB(fecha,"0000","0004"));
Map app_owner.*, Target app_owner.*;

No hay comentarios:

Amazon