In my blog about the new automatic schema evolution feature in GoldenGate 26ai, I was replicating the following table from Oracle to PostgreSQL:
CREATE TABLE autosch.t1 (
id NUMBER PRIMARY KEY,
name VARCHAR2(50),
amount NUMBER(10,2),
created DATE DEFAULT SYSDATE,
note VARCHAR2(20) DEFAULT 'added'
);
The replicat created a PostgreSQL table from an Oracle one during an initial load. It worked, but one choice was not mine: the NUMBER primary key became a varchar(50). Automatic Schema Evolution takes its datatypes from a default mapping, and the TYPEMAP option is how you override it.
Automatic schema evolution is a preview feature in GoldenGate 26ai: its syntax, messages and behavior can change before it becomes generally available, so the results below apply to the 23.26.3 release I tested.
Where the default mapping comes from
Each GoldenGate 26ai home ships the default mappings as one JSON file per source database and per target database. They are in $OGG_HOME/lib/utl/autoschema/MappingJSON, where MappingGenerator.py combines a source and a target file. For this example, the files are AutoSchemaOracleSourceMappings.json and AutoSchemaPostgreSQLTargetMappings.json.
Reading the two JSON files for an Oracle source and a PostgreSQL target, the default mappings that matter for the example table are:
| Oracle source type | PostgreSQL target type |
|---|---|
number(precision,scale) | decimal(precision,scale) |
number | varchar(precision), if the source data length is at most 10485760 |
number | text, if the value is still too large to be accommodated |
date | timestamp(precision) |
A NUMBER without precision maps to varchar, and a NUMBER(p,s) maps to decimal(p,s). This is why the key of my source table did not become a number.
For each test below, I drop autosch.t1 on PostgreSQL and start a new replicat, always named REPTM, on the same file.
Overriding one type
AUTOSCHEMAOPTIONS TYPEMAP must be written on a separate line, next to DDL AUTOSCHEMA INCLUDE ALL. The source type and the target type are separated by an equal sign. The option maps every occurrence of the source type to the given target type. Both types must be enclosed in single quotes, otherwise the replicat abends with OGG-30694:
REPLICAT REPTM
TARGETDB ogg_pg_01 USERIDALIAS pgalias DOMAIN OracleGoldenGate
DDL AUTOSCHEMA INCLUDE ALL
AUTOSCHEMAOPTIONS TYPEMAP 'number' = 'bigint'
MAP AUTOSCH.*, TARGET AUTOSCH.*;
The replicat report logs that the override was read:
2026-09-19T15:23:47.078+0000 INFO OGG-30632 Oracle GoldenGate Delivery for PostgreSQL, REPTM.prm: AutoSchemaOptions TypeMap is used, TypeNameMap: number -> bigint.
The table created in PostgreSQL, seen with \d autosch.t1 in psql, now shows a bigint as primary key
ogg_test_pg=# \d autosch.t1
Table "autosch.t1"
Column | Type | Collation | Nullable | Default
---------+--------------------------------+-----------+----------+---------
id | bigint | | not null |
name | character varying(50) | | |
amount | numeric(10,2) | | |
created | timestamp(0) without time zone | | |
note | character varying(20) | | |
Indexes:
"t1_pkey" PRIMARY KEY, btree (id)
The amount column type did not change, since 'number' matches the source type NUMBER without precision. NUMBER(10,2) is another source type, and is not affected by the TYPEMAP instruction.
Mapping several types with AUTOSCHEMAOPTIONS
When mapping multiple types, each mapping needs a dedicated AUTOSCHEMAOPTIONS line:
DDL AUTOSCHEMA INCLUDE ALL
AUTOSCHEMAOPTIONS TYPEMAP 'number' = 'bigint'
AUTOSCHEMAOPTIONS TYPEMAP 'date' = 'date'
AUTOSCHEMAOPTIONS TYPEMAP 'number(10,2)' = 'real'
Every entry is logged separately:
2026-09-19T16:29:07.403+0000 INFO OGG-30632 Oracle GoldenGate Delivery for PostgreSQL, REPTM.prm: AutoSchemaOptions TypeMap is used, TypeNameMap: date -> date.
2026-09-19T16:29:07.403+0000 INFO OGG-30632 Oracle GoldenGate Delivery for PostgreSQL, REPTM.prm: AutoSchemaOptions TypeMap is used, TypeNameMap: number -> bigint.
2026-09-19T16:29:07.403+0000 INFO OGG-30632 Oracle GoldenGate Delivery for PostgreSQL, REPTM.prm: AutoSchemaOptions TypeMap is used, TypeNameMap: number\(10,2\) -> real.
And this is the resulting table:
Column | Type | Collation | Nullable | Default
---------+-----------------------+-----------+----------+---------
id | bigint | | not null |
name | character varying(50) | | |
amount | real | | |
created | date | | |
note | character varying(20) | | |
All three overrides are applied. An interesting feature is that the replicat logs an OGG-03056 warning about the target column being smaller than the source column:
2026-09-19T16:29:07.419+0000 WARNING OGG-03056 Oracle GoldenGate Delivery for PostgreSQL, REPTM.prm: Source table AUTOSCH.T1 column CREATED data size exceeds the maximum target table autosch.t1 column created size. Automatic truncation is enabled for all tables/columns without further warnings.
As expected, mapping DATE to a PostgreSQL date loses the time part, and it can be seen in the target table:
id | name | amount | created | note
----+-------+--------+------------+-------
1 | row 1 | 10.25 | 2026-09-19 | added
2 | row 2 | 20.5 | 2026-09-19 | added
An Oracle DATE carries a time, so the default timestamp(0) mapping is the right one.
AUTOSCHEMAOPTIONS at the MAP level
The same option can be set on a MAP statement, between parentheses. It then only applies to the tables of that MAP statement instead of the whole replicat:
MAP AUTOSCH.*, TARGET AUTOSCH.*, AUTOSCHEMAOPTIONS (TYPEMAP 'number' = 'bigint');
2026-09-19T16:29:33.344+0000 INFO OGG-06506 Oracle GoldenGate Delivery for PostgreSQL, REPTM.prm: Wildcard MAP resolved (entry AUTOSCH.*): MAP "AUTOSCH"."T1", TARGET AUTOSCH."T1", AUTOSCHEMAOPTIONS (TYPEMAP 'number' = 'bigint').
2026-09-19T16:29:33.344+0000 INFO OGG-30632 Oracle GoldenGate Delivery for PostgreSQL, REPTM.prm: AutoSchemaOptions TypeMap is used, TypeNameMap: number -> bigint.
The table has a bigint key again. In this case, the other number columns outside of the MAP statement would keep the default varchar(50) mapping.
Remapping a single column
To change a single column, write the column name on the left side of the equal sign, instead of specifying the source type. The two forms work, first with the full name of the column:
AUTOSCHEMAOPTIONS TYPEMAP AUTOSCH.T1.NAME = 'text'
And at the MAP level, with the column name alone:
MAP AUTOSCH.T1, TARGET AUTOSCH.T1, AUTOSCHEMAOPTIONS (TYPEMAP NAME = 'text');
Both give the same table, with only name changed into text:
Column | Type | Collation | Nullable | Default
---------+--------------------------------+-----------+----------+---------
id | character varying(50) | | not null |
name | text | | |
amount | numeric(10,2) | | |
created | timestamp(0) without time zone | | |
note | character varying(20) | | |
To remap several columns on the same MAP, separate the mappings with commas inside the parentheses, and write TYPEMAP only once:
MAP AUTOSCH.T1, TARGET AUTOSCH.T1, AUTOSCHEMAOPTIONS (TYPEMAP NAME = 'text', NOTE = 'text');
Column | Type | Collation | Nullable | Default
---------+--------------------------------+-----------+----------+---------
id | character varying(50) | | not null |
name | text | | |
amount | numeric(10,2) | | |
created | timestamp(0) without time zone | | |
note | text | | |
A type and a column can be mixed in the same list. For example, AUTOSCHEMAOPTIONS (TYPEMAP 'number' = 'bigint', NAME = 'text') gives a bigint key and a text name.
To summarize
- The default mapping files are located in
$OGG_HOME/lib/utl/autoschema/MappingJSON. Check them before letting a replicat create tables. ANUMBERwithout precision becomes avarcharon PostgreSQL, for instance. - The override syntax is
AUTOSCHEMAOPTIONS TYPEMAP 'source_type' = 'target_type'. Use an equal sign, both types in single quotes, and one mapping per line. - A source type is matched as written. An override on
'number'does not change aNUMBER(10,2)column, which needs a separate'number(10,2)'entry. - On a
MAP, put the option between parentheses to limit it to those tables. For one column, useAUTOSCH.T1.NAME = 'text'globally orNAME = 'text'on theMAP. - Pay attention to
OGG-03056warnings: a target type smaller than the source, likeDATEtodate, truncates the data without stopping the initial load.