Bridging On-Premises Oracle Databases to ATP via OCI Object Storage

Share

1. Introduction

Oracle Data Pump (expdp / impdp) is the de-facto standard for extracting and loading data between Oracle databases. When the source is an on-premises Oracle EBS, E-Business Suite, or any legacy Oracle RDBMS and the target is Oracle Autonomous Transaction Processing (ATP) on OCI, the recommended staging layer is OCI Object Storage — a durable, scalable, and cost-efficient intermediate store that both worlds can read from and write to natively.

This article walks through the complete pipeline:

• Exporting data from a source Oracle DB into .dmp files

• Uploading those dump files to an OCI Object Storage bucket using Python

• Importing the dump directly into an ATP database table using impdp or DBMS_DATAPUMP

Code snippets, architecture notes, and production-readiness tips are included throughout.

2. When Is This Process Required?

This pipeline addresses several common scenarios in Oracle cloud adoption and migration projects:

2.1  Legacy EBS / On-Premises to Cloud Migration

Organizations migrating Oracle E-Business Suite R12 to Oracle Fusion Cloud Applications need to stage historical transactional data — GL journals, AR invoices, AP payments, inventory transactions — in ATP or ADW for reporting continuity. Data Pump is the fastest, most reliable extraction mechanism available on legacy Oracle instances.

2.2  Cross-Environment Data Refresh

Development and UAT teams frequently need production-like data snapshots. Rather than copying the full database, a selective schema or table-level dump can be exported, staged in Object Storage, and imported on demand into ATP dev/test instances.

2.3  Historical Data Archival

Regulatory requirements (SOX, VAT retention, local statutory rules) mandate retaining transactional data for 7–10 years. Periodic Data Pump exports staged in OCI Object Storage with lifecycle policies applied for Infrequent Access / Archive tiers provide a cost-efficient long-term retention model.

2.4  Disaster Recovery Seeding

In DR scenarios where RPO requirements are relaxed, nightly or weekly .dmp exports to Object Storage provide a recoverable baseline without the cost of Active Data Guard cross-region replication.

Scenario

Source

Target on OCI

EBS to Fusion Migration

Oracle EBS R12

ATP (Finance / SCM tables)

Dev/UAT Refresh

Production Oracle DB

ATP Dev instance

Archival

Any Oracle RDBMS

ADW + Object Storage Archive

DR Seeding

Primary Oracle DB

ATP Standby instance

3. Solution Architecture & Approach

The end-to-end pipeline consists of three logical stages:

 Source Oracle DB  →  OCI Object Storage Bucket  →  ATP Database Table 

Stage 1 — Export: Data Pump on Source DB

Run expdp on the source Oracle instance. Use the %L wildcard to auto-split large exports into multiple sequenced .dmp files capped at a defined file size (recommended ≤ 5 GB per file for Object Storage compatibility).

⚡  Use the HIGH or FAST service name and set PARALLEL = number of CPU cores for best export throughput.

Stage 2 — Stage: OCI Object Storage

OCI Object Storage acts as the neutral staging layer. It is accessible by both the source (via OCI CLI or REST) and the ATP target (via DBMS_CLOUD credential). Key design decisions:

• Bucket in the same OCI region as ATP to avoid egress charges

• Pre-Authenticated Request (PAR) or IAM credential for secure access

• Object prefix (virtual folder) per migration wave for clean organization

• Lifecycle policy to auto-delete staged dumps after import confirmation

Stage 3 — Load: impdp or DBMS_DATAPUMP into ATP

ATP supports two import mechanisms — the traditional impdp client utility (with a credential object pointing to the bucket) and the programmatic DBMS_DATAPUMP PL/SQL API. Both reference the dump file using its OCI Object Storage URI directly.

4. Step-by-Step Implementation

4.1  Export from Source Oracle Database

On the source Oracle server, run:

expdp system/password@SOURCEDB
schemas=APPS,GL,AR
dumpfile=ebs_export_%L.dmp
directory=DATA_PUMP_DIR
filesize=5GB
parallel=8
logfile=ebs_export.log

📁  This produces files: ebs_export_100.dmp, ebs_export_101.dmp, ... in DATA_PUMP_DIR.

4.2  Upload .dmp Files to OCI Object Storage (Python)

Install the OCI SDK and run the upload script. The script uses UploadManager for multipart uploads (handles files > 5 GB cleanly), parallel file uploads via ThreadPoolExecutor, and resume-safe skipping of already-uploaded files.

pip install oci tqdm 

Key code structure:

import oci
import os
import sys
CONFIG_FILE = r"C:\Users\Users.oci\config" # OCI config file path
NAMESPACE = "NAMESPACE" # oci os ns get
BUCKET_NAME = "BUCKET_NAME"
OBJECT_NAME = "*.dmp" # name it will have in OCI
FILE_PATH = r"C:\Users\Users\*.dmp" # local file path
PART_SIZE_MB = 256
PARALLEL = 5
CERT_FILE = r"C:\Users\Users.oci\corporate.cer" # ← your exported cert
def progress(bytes_uploaded):
file_size = os.path.getsize(FILE_PATH)
pct = (bytes_uploaded / file_size) * 100
done = int(50 * bytes_uploaded / file_size)
bar = '█' * done + '░' * (50 - done)
print(f"\r [{bar}] {pct:.1f}% "
f"({bytes_uploaded/10243:.2f} GB / {file_size/10243:.2f} GB)",
end="", flush=True)
def upload():
print("=" * 60)
print("OCI Object Storage — Large File Upload")
print("=" * 60)
print(f"File : {FILE_PATH}")
print(f"Bucket : {BUCKET_NAME}")
print(f"Object : {OBJECT_NAME}")
print(f"File Size : {os.path.getsize(FILE_PATH)/1024**3:.2f} GB")
print(f"Part Size : {PART_SIZE_MB} MB")
print(f"Parallel : {PARALLEL} threads")
print("=" * 60)

if not os.path.exists(FILE_PATH):
    print(f"ERROR: File not found: {FILE_PATH}")
    sys.exit(1)

config    = oci.config.from_file(CONFIG_FILE)
os_client = oci.object_storage.ObjectStorageClient(
    config,
    verify = CERT_FILE    # ← use corporate cert
)

upload_mgr = oci.object_storage.UploadManager(
    os_client,
    allow_multipart_uploads          = True,
    allow_parallel_multipart_uploads = True
)

print("\nUploading...")
response = upload_mgr.upload_file(
    namespace_name         = NAMESPACE,
    bucket_name            = BUCKET_NAME,
    object_name            = OBJECT_NAME,
    file_path              = FILE_PATH,
    part_size              = PART_SIZE_MB * 1024 * 1024,
    parallel_process_count = PARALLEL,
    progress_callback      = progress
)

print(f"\n\nUpload complete!")
print(f"ETag : {response.data.etag}")

head       = os_client.head_object(NAMESPACE, BUCKET_NAME, OBJECT_NAME)
oci_size   = int(head.headers.get('content-length', 0))
local_size = os.path.getsize(FILE_PATH)

print(f"Local size : {local_size:,} bytes")
print(f"OCI size   : {oci_size:,} bytes")
print(f"Match      : {'✅ YES' if oci_size == local_size else '❌ NO — reupload!'}")
print("=" * 60)

if name == "main":
upload()

♻️  Run with --no-skip flag to force re-upload on retry. Default behavior skips already-present objects.

4.3  Create OCI Credential in ATP

Before importing, create a credential object in ATP that authenticates to OCI Object Storage:

BEGIN
  DBMS_CLOUD.CREATE_CREDENTIAL(
    credential_name => 'OCI_DUMP_CRED',
    username        => 'oracleidentitycloudservice/user@example.com',
    password        => '<auth_token>'   -- OCI Auth Token
  );
END;

/

🔑  Generate the Auth Token from OCI Console → Identity → Users → Auth Tokens. It acts as the password above.

4.4  Import into ATP Using impdp

From a client machine with Oracle Instant Client + Data Pump utilities, run impdp pointing the dump file directly at the Object Storage URI:

impdp admin/password@ATP_HIGH
  credential=OCI_DUMP_CRED
  dumpfile=https://namespace.objectstorage.us-ashburn-1.oci.customer-oci.com/
          n/namespace/b/EBS_MIGRATION_DUMPS/o/ebs_dumps/ebs_export_%l.dmp
  parallel=16
  table_exists_action=REPLACE
  transform=segment_attributes:n
  exclude=cluster,db_link
  logfile=atp_import.log

4.5  Alternative: DBMS_DATAPUMP (PL/SQL, No Client Required)

If you cannot install Oracle client tools, use the DBMS_DATAPUMP API entirely from within ATP SQL Worksheet or SQLcl:

DECLARE
  h  NUMBER;
BEGIN
  h := DBMS_DATAPUMP.OPEN(
         operation  => 'IMPORT',
         job_mode   => 'SCHEMA',
         job_name   => 'EBS_IMP_JOB');
 
  DBMS_DATAPUMP.ADD_FILE(
    handle    => h,
    filename  => 'https://namespace.objectstorage.us-ashburn-1.oci.customer-oci.com/
                  n/namespace/b/EBS_MIGRATION_DUMPS/o/ebs_dumps/ebs_export_%l.dmp',
    directory => 'OCI_DUMP_CRED',
    filetype  => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE);
 
  DBMS_DATAPUMP.SET_PARALLEL(handle => h, degree => 8);
  DBMS_DATAPUMP.START_JOB(h);
END;
/

5. Validation & Post-Load Checks

After the import, run these checks in ATP to validate completeness:

-- Check import job status
SELECT job_name, state, degree, error_count
FROM   dba_datapump_jobs;

-- Row count validation against source
SELECT table_name, num_rows
FROM   dba_tables
WHERE  owner = 'GL'
ORDER  BY table_name;

-- Object Storage upload verification (Python)
response = client.list_objects(namespace, BUCKET, prefix='ebs_dumps/')
print(f'{len(response.data.objects)} objects staged in bucket')

 

✅  Cross-check num_rows with source DB counts as part of migration UAT sign-off.

6. Production Considerations & Best Practices

 

Area

Recommendation

File Size

Keep individual .dmp files ≤ 5 GB using filesize parameter. Object Storage API supports up to 50 GB but smaller files enable parallel streams.

Encryption

Use ENCRYPTION_PWD_PROMPT=YES on expdp. Pass the same prompt on impdp. Stored credentials in DBMS_CLOUD do not expose the encryption key.

Network

Use OCI FastConnect or VPN for on-premises uploads. For compute-to-compute within OCI, enable Service Gateway to avoid public internet routing.

Parallelism

Set PARALLEL on both expdp and impdp to match CPU count. For ATP, use the HIGH service name for maximum resource allocation.

Lifecycle Policy

Add an Object Storage lifecycle rule to delete dump objects 30 days after creation, preventing cost accumulation from orphaned files.

Resume Safety

The Python upload script skips already-uploaded objects by default. Use --no-skip only when explicitly re-staging after a source data change.

 

7. Common Errors & Troubleshooting

 

ORA-39001 / ORA-39000 — Invalid argument on impdp

Cause: Incorrect Object Storage URI format or credential name mismatch. Check that the URI uses the OCI Dedicated Endpoint format (namespace.objectstorage.region.oci.customer-oci.com) and that the credential is created in the same ATP schema running the import.

ORA-20401 — Credential not found (DBMS_CLOUD)

Cause: The credential was created in a different schema. Grant access or recreate under ADMIN. Verify with: SELECT credential_name FROM all_credentials;

Zero-byte .dmp files in Object Storage console

Cause: This is expected behaviour when exporting directly via Data Pump to Object Storage. The actual data is in chunk files (.dmp_aaaaaa, .dmp_aaaaab, etc.). Use impdp or Swift/curl — not the OCI Console download button — to retrieve full files.

Python upload fails with 401 Unauthorized

Cause: OCI config fingerprint or private key path mismatch. Run: oci iam user get --user-id <your_ocid> to validate config. On Compute VMs, switch to Instance Principal auth by removing the config file argument.

8. Summary

The pipeline of Oracle Data Pump export → OCI Object Storage staging → ATP import is the standard, Oracle-recommended approach for moving bulk schema data into Autonomous Database. It avoids database links, intermediate servers, and proprietary ETL tooling.

The three-stage approach provides:

• Decoupling — source and target databases never connect directly

• Durability — Object Storage retains the dump as a recoverable point

• Scalability — multipart uploads and parallel impdp scale with data volume

• Auditability — timestamped log files at every stage for migration sign-off 

The Python automation layer brings resume-safety, structured logging, and parallel throughput that the OCI CLI alone does not provide out of the box — making it the preferred choice for production migration involving dozens of schemas or terabytes of data.

 

 

Read more