The issue was related to incorrect handling of unused columns during such loads and can cause incorrect data getting loaded into a database under certain conditions.
I tried to reproduce the issue using one database in my setup but wasn't able to do that and stuck with two databases.
I used Oracle Database 12.1.0.2 with DBBP 12.1.0.2.160419 applied and GoldenGate 12.2.0.1.160419 Patch Set.
I'm going to use two database in my test case, let it be SOURCE and TARGET. Firstly, let's create a test schema with a single table populating it with some data:
DBA@SOURCE> grant create session, create table, unlimited tablespace to tc identified by tc;
Grant succeeded.
DBA@SOURCE> conn tc/tc@source
Connected.
TC@SOURCE>
SQL> create table direct_load(
2 column1 int,
3 unused1 int,
4 column2 int,
5 column3 int);
Table created.
TC@SOURCE>
TC@SOURCE> insert into direct_load values (1, 0, 2, 3);
1 row created.
TC@SOURCE> commit;
Commit complete.
TC@SOURCE> select *
2 from direct_load;
COLUMN1 UNUSED1 COLUMN2 COLUMN3
---------- ---------- ---------- ----------
1 0 2 3
Secondly, we are making column "unused1" unused:
TC@SOURCE> alter table direct_load set unused column unused1; Table altered.Now I will execute the same DDL commands into TARGET database, which is obviously what GoldenGate server will do if we setup DDL replication:
Consider the scenario when we have decided to resynchronize data in TARGET database from SOURCE database.
I'm going to remove all rows from the table in TARGET database first:
TC@TARGET> truncate table direct_load; Table truncated.Proceed with GoldenGate setup. I want to use GoldenGate Direct Bulk Load to SQL*Loader capability to move the data from SOURCE database to TARGET database.
Let's use IRTC - as a name of the initial load replicat and IETC - as a name of the initial load extract:
-- setup initial load replicat GGSCI (ogg-test) 2> edit params irtc -- UserIdAlias may be customized accordingly to your environment or simply use a username/password pair Replicat irtc AssumeTargetDefs UserIdAlias target_ogg_replicat DiscardFile ./dirrpt/irtc.dsc, Purge -- I want to use Direct Bulk Load BulkLoad -- I used PDB "orcl" for my experiments: Map orcl.tc.*, target orcl.tc.*; -- setup initial load extract GGSCI (ogg-test) 149> edit params ietc Extract ietc RmtHost ogg-test, MgrPort 7809 RmtTask Replicat, Group irtc UserIdAlias source_ogg_extract Table orcl.tc.direct_load; -- let's create GoldenGate processes GGSCI (ogg-test) 116> add replicat irtc SpecialRun REPLICAT added. GGSCI (ogg-test) 117> add extract ietc SourceIsTable EXTRACT added.The setup has been finished. Right now we can try to perform initial load:
GGSCI (ogg-test) 15> info i*tc, tasks
EXTRACT IETC Initialized 2016-09-01 08:54 Status STOPPED
Checkpoint Lag Not Available
Log Read Checkpoint Not Available
First Record Record 0
Task SOURCEISTABLE
REPLICAT IRTC Initialized 2016-09-01 08:54 Status STOPPED
Checkpoint Lag 00:00:00 (updated 00:00:28 ago)
Log Read Checkpoint Not Available
Task SPECIALRUN
GGSCI (ogg-test) 16> start extract ietc
Sending START request to MANAGER ...
EXTRACT IETC starting
The load has completed pretty soon:
GGSCI (ogg-test) 17> info i*tc, tasks
EXTRACT IETC Last Started 2016-09-01 08:55 Status STOPPED
Checkpoint Lag Not Available
Log Read Checkpoint Table ORCL.TC.DIRECT_LOAD
2016-09-01 08:55:27 Record 1
Task SOURCEISTABLE
REPLICAT IRTC Initialized 2016-09-01 08:54 Status STOPPED
Checkpoint Lag 00:00:00 (updated 00:02:09 ago)
Log Read Checkpoint Not Available
Task SPECIALRUN
ggserr.log file doesn't raise any concerns:
Yes, I had a warning like this:
2016-09-01 08:55:12 WARNING OGG-00752 Oracle GoldenGate Capture for Oracle, ietc.prm: Failed to validate table ORCL.TC.DIRECT_LOAD. Likely due to existence of unused column. Please make sure you use sourcedefs in downstream Replicat, or the target table has exactly the same unused columns when using ASSUMETARGETDEFS or DDL replication.But I obviously didn't violate it as the source and the target table has the same unused columns.
Let's see what has loaded into TARGET database:
TC@TARGET> select * from direct_load;
COLUMN1 COLUMN2 COLUMN3
---------- ---------- ----------
1 2
That's not I wanted to load and that differs from the original table in SOURCE database:
TC@SOURCE> select * from direct_load;
COLUMN1 COLUMN2 COLUMN3
---------- ---------- ----------
1 2 3
Clearly the data from COLUMN2 got loaded into COLUMN3 and I didn't get any errors afterwards leaving my database with "wrong" data.That's the worst scenario. Originally I faced the issue while I was moving a bunch of data from one database to another using GoldenGate.
The load got ABENDED with ORA-01840 as in my case COLUMN3 had a DATE datatype which may be easily reproduced by the following code:
SQL> select to_date('2', 'yyyy-mm-dd hh24:mi:ss') from dual;
select to_date('2', 'yyyy-mm-dd hh24:mi:ss') from dual
*
ERROR at line 1:
ORA-01840: input value not long enough for date format
Of course, if you are lucky, you may get some other datatype conversion errors. If you are not, you may end with wrong data in your database and it may take a while before you find the problem.A few words about workarounds.
In this simple scenario, which I have written just for demonstration purposes, it was enough to drop unused columns in TARGET database:
TC@TARGET> alter table direct_load drop unused columns; Table altered.