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.*;

Migraciones con mínimo tiempo de parada con Oracle GoldenGate.

Últimamente estoy enfrentando migraciones que suponen cambios de plataforma, que los clientes utilizan para subir la base de datos de versión. Así pues, bases de datos en solaris versión Oracle10g (10.1 por ejemplo) que han de migrarse a un entorno Linux Oracle11g ó Oracle10g (versión 10.2).

Si la plataforma del sistema operativo fuera la misma (de solaris a solaris o de linux a linux) y la migración no implicase un cambio de versión, una de las opciones recomendadas es duplicar la base de datos, convertir el clon duplicado en base de datos standby, aplicar los logs en el momento de la puesta en producción y abrir la base de datos duplicada como principal.

Si hay subida de versión, en la máquina destino debe haber dos juegos de binarios: el mismo que el de origen, para realizar la restauración, y el juego de binarios de la nueva versión. Así, con el juego de binarios primero se realiza el duplicado y restauración, y con el segundo se abre la base de datos en modo «migrate» y se ejecutan los scripts de upgrade. Mientras dure el proceso la base de datos principal ha de estar parada y eso es un obstáculo.

Si bien las arquitecturas de sistema operativo son diferentes será necesario comprobar si el «endian» es distinto entre las dos plataformas. Existen dos tipos de endian, el pequeño y el grande. Entre plataformas de un mismo endian, basta con duplicar con RMAN la base de datos, pero si el endian es distinto (de little a big, o de big a little) requiere además convertir los ficheros y realizar la migración transportando tablespaces.

SQL> select * from v$transportable_platform
  2  order by endian_format;

PLATFORM_ID PLATFORM_NAME                            ENDIAN_FORMAT
———– —————————————- ————–
          3 HP-UX (64-bit)                           Big
          6 AIX-Based Systems (64-bit)               Big
         18 IBM Power Based Linux                    Big
          2 Solaris[tm] OE (64-bit)                  Big
          4 HP-UX IA (64-bit)                        Big
         16 Apple Mac OS                             Big
          1 Solaris[tm] OE (32-bit)                  Big
          9 IBM zSeries Based Linux                  Big
         17 Solaris Operating System (x86)           Little
         19 HP IA Open VMS                           Little
         20 Solaris Operating System (x86-64)        Little
         12 Microsoft Windows x86 64-bit             Little
         13 Linux x86 64-bit                         Little
          8 Microsoft Windows IA (64-bit)            Little
         21 Apple Mac OS (x86-64)                    Little
         11 Linux IA (64-bit)                        Little
          5 HP Tru64 UNIX                            Little
         10 Linux IA (32-bit)                        Little
          7 Microsoft Windows IA (32-bit)            Little
         15 HP Open VMS                              Little

20 filas seleccionadas.

Existen varias soluciones para hacer una migración de este tipo con mínimo tiempo de parada, como utilizar streams o utilizar un dataguard lógico, pero Oracle GoldenGate es definitivamente uno de los mejores métodos y más versátiles para migrar tanto bases de datos enteras, como esquemas, realizando además cambios de versión y de plataforma sincronizando lógicamente dos entornos.

Los pasos a seguir serían los siguientes, tomando nodo1 y nodo2 como los dos servidores, origen y destino.

1.- Descargar el software de Oracle GoldenGate de eDelivery   http://edelivery.oracle.com  y descomprimirlo en ambos servidores.
(el registro es gratuíto, y su descarga con fines no comerciales también!)

host1@oracle $ ./ggsci
Oracle GoldenGate Command Interpreter for Oracle
Version 11.2.1.0.1 OGGCORE_11.2.1.0.1_PLATFORMS_120423.0230_FBO
Solaris, sparc, 64bit (optimized), Oracle 10g on Apr 24 2012 09:06:57
Copyright (C) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
GGSCI (host1) 1> create subdirs
Creating subdirectories under current directory /opt/oracle/product/OracleGG
Parameter files                /opt/oracle/product/OracleGG/dirprm: already exists
Report files                   /opt/oracle/product/OracleGG/dirrpt: created
Checkpoint files               /opt/oracle/product/OracleGG/dirchk: created
Process status files           /opt/oracle/product/OracleGG/dirpcs: created
SQL script files               /opt/oracle/product/OracleGG/dirsql: created
Database definitions files     /opt/oracle/product/OracleGG/dirdef: created
Extract data files             /opt/oracle/product/OracleGG/dirdat: created
Temporary files                /opt/oracle/product/OracleGG/dirtmp: created
Stdout files                   /opt/oracle/product/OracleGG/dirout: created

2.- Chequear que la base de datos origen está en modo ARCHIVELOG


ARCHIVE LOG LIST;
3.- Activar el suplemental logging en la base de datos.

SELECT force_logging, supplemental_log_data_min FROM v$database;
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
ALTER DATABASE FORCE LOGGING;
ALTER SYSTEM SWITCH LOGFILE;
4.-Crear el usuario GoldenGate en la base de datos origen.

CREATE USER oggadm1 IDENTIFIED BY “13c1sa”;
GRANT dba TO oggadm1;
5.-Comprobar la visibilidad entre las bases de datos (todas).

host1@oracle $ tnsping b_new
TNS Ping Utility for Solaris: Version 10.2.0.5.0 – Production on 30-APR-2013 12:23:25
Copyright (c) 1997,  2010, Oracle.  All rights reserved.
Used parameter files:
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = host2)(PORT = 1521))) (CONNECT_DATA = (SID = BBDD2)))
OK (320 msec)

6.-Configurar manager.

host1@oracle $ more GLOBALS
CheckpointTable oggadm1.oggchkp
host1@oracle $ more startup.oby
DBLogin UserID oggadm1@B, Password 13c1sa
Start Mgr
Info Mgr
Info CheckpointTable
Set Editor vi
GGSCI (host1) 1> Edit Param mgr
«/opt/oracle/product/OracleGG/dirprm/mgr.prm» [New file]
Port 15002
PurgeOldExtracts ./dirdat/*, UseCheckpoints
GGSCI (host1) 1> obey startup.oby
GGSCI (host1) 2> DBLogin UserID oggadm1@B, Password 13c1sa
Successfully logged into database.
GGSCI (host1) 3> Start Mgr
MGR is already running.
GGSCI (host1) 4> Info Mgr
Manager is running (IP port host1.15001).
GGSCI (host1) 5> Info CheckpointTable
No checkpoint table specified, using GLOBALS specification (oggad1.oggchkp)…
Checkpoint table oggad1.oggchkp does not exist.
GGSCI (host1) 6> Set Editor vi
7.-Crear la tabla de checkpoints.

GGSCI (host1) 7> Add CheckpointTable
No checkpoint table specified, using GLOBALS specification (oggadm1.oggchkp)…
Successfully created checkpoint table oggadm1.oggchkp.

8.- Crear el proceso EXTRACT

GGSCI (host1) 9> edit param extr
host1@oracle $ more /opt/oracle/product/OracleGG/dirprm/extr.prm
Extract extr
UserID oggadm1@B, Password 13c1sa
ExtTrail ./dirdat/aa
Table USUARIO1.*;
Table USUARIO2.*;
Table USUARIO3.*;
Table USUARIO4.*;

GGSCI (host1) 2> Add Extract extr, TranLog, Begin Now

EXTRACT added.
GGSCI (host1) 18> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING
EXTRACT     STOPPED     EXTR        00:00:00      00:00:44

9.- Arrancar el proceso EXTRACT en el servidor origen. Una vez arrancado lanzar un log switch y un EXPORT DATA PUMP de la base de datos principal sobre la réplica con la opción FLASHBACK_SCN=xxxxxxx. En este caso es el 501308592, correspondiente al FIRST_CHANGE del último redolog online.
10.- Añadir trandata para tablas en el servidor origen.
Add TranData
Add TranData USUARIO1.*
Add TranData USUARIO2.*
Add TranData USUARIO3.*
Add TranData USUARIO4.*




11.- Configurar manager en servidor de replica (pasos 6 y 7)

12.- Configurar pump en servidor principal.

GGSCI (host1) 2> edit param pump
«/opt/oracle/product/OracleGG/dirprm/pump.prm» [New file]
Extract pump
RmtHost host2, MgrPort 15002, Compress
RmtTrail ./dirdat/ab
Passthru
Table USUARIO1.*;
Table USUARIO2.*;
Table USUARIO3.*;
Table USUARIO4.*;

«/opt/oracle/product/OracleGG/dirprm/pump.prm» [New file] 8 lines, 969 characters
GGSCI (host1) 3> Add Extract pump, ExtTrailSource ./dirdat/aa
EXTRACT added.
GGSCI (host1) 4> Add RmtTrail ./dirdat/ab, Extract pump, megabytes 5
RMTTRAIL added.
GGSCI (host1) 5> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING
EXTRACT     RUNNING     EXTR        00:00:00      00:00:02
EXTRACT     STOPPED     PUMP        00:00:00      00:00:11


13.- Configurar replicat en servidor replica.

GGSCI (host2) 10> edit param repl
Replicat repl
UserID oggadm1@B, password 13c1sa
AssumeTargetDefs
DiscardFile ./dirrpt/repl.dsc
Map USUARIO1.*, Target USUARIO1.*;
Map USUARIO2.*, Target USUARIO2.*;
Map USUARIO3.*, Target USUARIO3.*;
Map USUARIO4.*, Target USUARIO4.*;

GGSCI (host2) 11> Add Replicat repl, ExtTrail ./dirdat/ab
REPLICAT added.
GGSCI (host2) 12> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING
REPLICAT    STOPPED     REPL        00:00:00      00:00:06

14.- Arrancar pump en servidor principal.

GGSCI (host1) 7> start extract pump
Sending START request to MANAGER …
EXTRACT PUMP starting
GGSCI (host1) 8> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING
EXTRACT     RUNNING     EXTR        00:00:00      00:00:08
EXTRACT     RUNNING     PUMP        00:00:00      00:13:38
GGSCI (host1) 9> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING
EXTRACT     RUNNING     EXTR        00:00:00      00:00:08
EXTRACT     RUNNING     PUMP        00:00:00      00:00:09
14.- Importar el fichero de Export Data Pump generado en el paso 9.


15.- Arrancar replicat en replica al SCN de la exportación.

GGSCI (host2) 16> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING
REPLICAT    STOPPED     REPL        00:00:00      00:06:11
GGSCI (host1) 7> Start Replicat, aftercsn 501308592
GGSCI (host2) 9> Start Replicat repl, aftercsn 501308592
Sending START request to MANAGER …
REPLICAT REPL starting
GGSCI (host2) 10> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING
REPLICAT    RUNNING     REPL        00:00:00      00:00:06



Una vez las dos bases de datos están sincronizadas, toda la información del servidor principal se propaga a la base de datos réplica, que es idéntica en estructura a la base de datos principal. En el momento de la puesta en producción simplemente hay que cambiar los clientes para dirigirlos a la réplica.