Skip to main content
KinetiStack™

Oracle compatibility

Supported Oracle versions

VersionStatusCI coverage
Oracle 19cSupported (all editions: SE2, EE, Autonomous Database)Validated pre-release against the same JDBC + metadata API surface CI exercises continuously
Oracle 21cSupported (all editions: SE2, EE, Express, Autonomous)Continuous integration on every commit
Oracle 23aiSupported (all editions: SE2, EE, Free, Autonomous)Continuous integration on every commit

All three versions are exercised against the same code paths. Newer Oracle releases (24+) ride the same JDBC dialect and are expected to work the same day they ship.

Compatibility surface

The extractor uses standard Oracle JDBC (ojdbc11, 23.5 driver) and the standard DBMS_* metadata packages — both have been stable since Oracle 9i. The specific features the extractor depends on:

APIAvailable sinceWhy we use it
DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER9iPins a consistent SCN per table or globally
AS OF SCN ... flashback queries10gLets parallel readers see the same logical snapshot
DBMS_METADATA.GET_DDL9iCaptures DDL for replay during restore
DBMS_LOB (READ, GETLENGTH)8iLOB-aware partitioned reads
ORA_HASH(ROWID)10gPartition pseudo-key for tables without a PK
ALL_TABLES, ALL_CONSTRAINTS, ALL_TAB_COLUMNS8iCatalog discovery

Because every feature predates 19c, all editions of 19c+ are supported without modification — SE, SE2, EE, Express, and Autonomous all expose the same APIs.

Deployment topologies

The product talks to Oracle over standard JDBC. Any topology that exposes a JDBC listener works. Notes for the most common cases:

Standard single-instance Oracle (default)

Default topology. Connect via oracleHost:oraclePort (defaults to TCP 1521). All editions behave identically from the extractor’s perspective.

Oracle RAC (Real Application Clusters)

Connect via the SCAN listener (<scan-name>:1521). The JDBC driver handles its own load balancing across instances. For deterministic single-instance affinity (e.g. when you need session affinity for a specific UNDO segment during a long whole_db_scn extract), point oracleHost at a specific node’s VIP. No RAC-specific configuration is required — standard JDBC TAF and FCF work transparently.

Oracle Exadata

From the JDBC client’s perspective Exadata is just a tuned Oracle instance — Smart Scan, HCC, and storage offload are server-side and transparent. HCC-compressed tables (BASIC, OLTP, QUERY HIGH/LOW, ARCHIVE HIGH/LOW) decompress transparently during JDBC fetch — no special handling needed.

Oracle Autonomous Database (ADW / ATP)

ADW and ATP enforce TLS connections (port 1522 with TLS or 2484 with mTLS) and prefer Oracle Wallet for authentication. Three connection strategies:

Option 1 — Wallet via env vars (v0.9.2+): the extractor honours ORACLE_TNS_ADMIN and ORACLE_TNS_ALIAS. When both are set, the JDBC URL switches from host:port/service to TNS-alias mode and the driver reads cwallet.sso + tnsnames.ora from TNS_ADMIN:

# 1. Download the wallet bundle (e.g. Wallet_MYDB.zip) from the OCI
#    console for your Autonomous Database.

# 2. Upload the bundle to Key Vault as a base64 secret.
KV=$(az resource list -g <rg> --resource-type Microsoft.KeyVault/vaults \
       --query '[0].name' -o tsv)
base64 -w0 Wallet_MYDB.zip | az keyvault secret set \
   --vault-name "$KV" --name oracle-wallet --file /dev/stdin

# 3. Add a startup script to the extractor Container Apps Job that
#    pulls the secret, base64-decodes, unzips to /tmp/oracle-wallet,
#    and exports:
#       ORACLE_TNS_ADMIN=/tmp/oracle-wallet
#       ORACLE_TNS_ALIAS=mydb_high
#    (Aliases live in tnsnames.ora — typically
#     <dbname>_low / _medium / _high / _tp / _tpurgent.)

The wallet bundle carries the user credentials, so oracleUser / oraclePassword become advisory; Bicep still requires them as template params — pass placeholder values (oracleUser=wallet, oraclePassword=wallet).

Option 2 — Password auth via public endpoint: create a database user with a password and connect via the public endpoint using standard JDBC. ADW accepts password auth alongside wallet auth on the same listener — set oracleHost, oraclePort=1521, oracleService=<dbname>_low. No wallet needed; simpler operationally but exposes the DB to public internet (mitigate with the ADW ACL list).

Option 3 — Private endpoint to ADW: use Oracle’s Database Service Gateway to expose ADW on a private endpoint reachable from the CAE subnet. Then either option 1 or option 2 connects over the private path.

Transparent Data Encryption (TDE)

  • Tablespace-level TDE: fully transparent to JDBC. Rows arrive at the client in cleartext (subject to the source user’s grants). No configuration needed on the extractor side.
  • Column-level TDE (DBMS_CRYPTO-managed): also transparent to JDBC. The extracted Parquet contains the cleartext values; if your threat model requires those to stay encrypted at rest in ADLS, set lifecycleProfile: 'compliance' (enables WORM + storage encryption at rest). Parquet Modular Encryption (column-level encryption inside the Parquet file itself) is on the v2.0 roadmap for customers needing key-managed isolation per archived column.

Pluggable database (PDB) extraction

Connect to a PDB by setting oracleService to the PDB service name (e.g. ORCLPDB1), not the CDB root. Multi-PDB extraction in a single job is not supported today — run one extract per PDB. The whole_db_scn consistency mode is scoped to the PDB you’re connected to.

The extractor reads DBA_TAB_COLUMNS to discover columns; tables exposed via synonyms that point at a remote DB-link are not automatically followed. To archive those, materialize them locally (CTAS) before the extract, or add the remote schema to defaultSchemas if your user has the right grants on the remote side.

Data-type and LOB handling

The extractor uses spark.read.jdbc for ordinary columns and a separate LOB-aware partitioned read for tables that contain LOB columns. Round-trip behavior for the Oracle types we’ve validated:

Oracle typeExtract behaviorRestore behaviorNotes
NUMBER (precision/scale set)round-trips as Spark Decimal(p,s)preservedexact
NUMBER (no precision/scale)coerced to Decimal(38,10) by Sparkpreservedthe JDBC type code 2 with prec=0 forces Spark’s decimal default — rounding at 10 fractional digits
INTEGER, FLOAT, BINARY_FLOAT, BINARY_DOUBLESpark numeric typespreservedexact
VARCHAR2, NVARCHAR2, CHAR, NCHARSpark String (UTF-8)preservedNVARCHAR2 character set normalized to AL32UTF8
DATESpark Timestamp (Oracle DATE has time component)preserved as DATEday-level resolution preserved
TIMESTAMPSpark Timestamppreservednanosecond precision is truncated to microsecond by Spark (Parquet INT96/INT64 limit)
TIMESTAMP WITH TIME ZONESpark Timestamppreserved as TIMESTAMPzone info is lost — values normalized to session zone (oracle.jdbc.timezoneAsRegion=false is set to make this deterministic)
TIMESTAMP WITH LOCAL TIME ZONESpark Timestamppreservedsession-zone-relative on both ends
INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECONDSpark CalendarIntervalTyperestored as INTERVALround-trips
CLOB, NCLOBLOB-mode read, materialized as Spark Stringrestored via setBigStringTryClob=true2GB ceiling per row (Spark string limit). Larger CLOBs fail with OutOfMemoryError — rare in practice; for >2GB values, copy via a separate JDBC path.
BLOBLOB-mode read, Spark Binarypreserved2GB ceiling, same as CLOB
RAW(n ≤ 2000)Spark Binarypreservedexact
LONG, LONG RAW (deprecated)Spark String / Binaryrestored if target column is LONG or LOBdeprecated by Oracle since 8i — convert to CLOB/BLOB on source
BFILENOT extracted (server-side file pointer)n/addl.sql preserves the column declaration; the pointer becomes a dangling reference on restore. Avoid archiving tables with active BFILE columns.
XMLType (binary storage)LOB-mode read, Spark Stringpreserved as XMLTypetextual round-trip; schema validation is not re-applied
XMLType (CLOB storage, deprecated)same as CLOBsame as CLOB2GB ceiling
Object types / nested tables / VARRAYNOT supportedn/aJDBC returns these as STRUCT types Spark cannot serialize to Parquet. Flatten on source or exclude via TABLES_EXCLUDE.
JSON (23ai native)Spark String (textual JSON)preserved as JSON columnrestore requires Oracle 21c+
ROWID, UROWIDSpark Stringpreserved as VARCHAR2row IDs are server-instance-specific; restored values are not valid in the target DB

When to plan around the surface

  • CLOB > 2GB: Spark’s StringType is bounded at 2GB regardless of the underlying CLOB. If your tables have >2GB single values, the extract for that row will fail with OutOfMemoryError or IllegalArgumentException (depending on the driver path). Workaround: exclude those tables and copy them via expdp + DBMS_LOB.READ instead.

  • BFILE: We do NOT extract the file contents — only the metadata pointer. After restore, the BFILE column points at a directory that doesn’t exist in the target environment. Pre-stage the files via a separate channel or exclude these tables.

  • Object types / UDTs: Unsupported. Flatten or exclude.

  • Encrypted columns (TDE column encryption): Transparent to the driver — extracted in cleartext (subject to the source user’s grants). Restore preserves the cleartext; re-encrypt at the target if required.

Operational notes per version

Historical Oracle issues that could affect operations:

SymptomWorkaroundAffected versions
ORA-01555 snapshot too old on long-running extractsUse per_table_scn (default) instead of whole_db_scn; bump UNDO_RETENTION on the source DBAll
JDBC-XA driver crash with TIMESTAMP WITH LOCAL TIME ZONEoracle.jdbc.timezoneAsRegion=false is set automatically in extract.py19c
DBMS_METADATA.GET_DDL returns NULL for objects you don’t ownThe extractor user needs SELECT_CATALOG_ROLE or per-object SELECT — see the Quickstart grant blockAll
Partitioned table DDL contains STORAGE clauses that the target tablespace cannot honorrestore.py strips top-level STORAGE clauses; nested partition specs may still need manual edit of ddl.sql before restore21c, 23ai
DROP TABLE ... CASCADE CONSTRAINTS racing across parallel restore threadsrestore.py auto-serializes when DROP_IF_EXISTS=true (concurrent=1). For faster reruns, drop the target schema yourself once, then restore with parallelism.All