oracle_fdw
1. Overview
oracle_fdw is an independently maintained foreign data wrapper that lets IvorySQL read and modify tables in a remote Oracle database through foreign tables. Neither the wrapper nor the Oracle client is bundled with IvorySQL; install both separately.
This adaptation was verified with IvorySQL master (based on PostgreSQL 19beta1, commit 069766efa8ca), oracle_fdw 2.9.0 (ORACLE_FDW_2_9_0, commit 3ea9a4522c44), Oracle AI Database 26ai Free 23.26.3.0.0, Oracle client 23.26.3.0.0, and Debian Bookworm x86_64. The findings apply to this combination; other IvorySQL releases and Oracle versions need separate validation.
2. Verified compatibility
The same connection, foreign-table, and read/write tests passed through three entry points: a native PostgreSQL-mode cluster, the PostgreSQL port of an Oracle-mode cluster (session dialect pg), and that cluster’s Oracle port ivorysql.port (session dialect oracle). All 24 TAP subtests passed on the unmodified IvorySQL baseline. The tested versions therefore need neither an IvorySQL core change nor a PgDialectExtensions entry to run CREATE EXTENSION oracle_fdw.
| Area | Result |
|---|---|
Installation and session state |
The extension installs through all three entry points; |
Queries and types |
|
Writes and transactions |
|
Privileges and connections |
User-mapping and table-privilege boundaries, session isolation, and reconnect after disconnect passed |
3. Prerequisites
-
Install server development headers and
pg_configfor the running IvorySQL version, a C compiler, and GNU make. -
Install Oracle Call Interface (OCI) headers and shared libraries and set
ORACLE_HOME. The IvorySQL server process must also be able to load the OCI libraries at runtime. -
Provide an Oracle instance reachable from the IvorySQL server and a dedicated Oracle account with only the required table privileges. The tested character set was
AL32UTF8.
When installing oracle_fdw 2.9.0, always select IvorySQL’s pg_config, rather than the system PostgreSQL path:
git clone --branch ORACLE_FDW_2_9_0 \
https://github.com/laurenz/oracle_fdw.git
cd oracle_fdw
export ORACLE_HOME=/path/to/oci-home
make PG_CONFIG=/path/to/ivorysql/bin/pg_config
sudo make PG_CONFIG=/path/to/ivorysql/bin/pg_config install
The IvorySQL service environment must also find $ORACLE_HOME/lib, using the operating-system dynamic linker configuration or the service’s LD_LIBRARY_PATH. After checking that pg_config --version matches the running IvorySQL instance, run the following in each IvorySQL database that needs Oracle access:
CREATE EXTENSION oracle_fdw;
SELECT oracle_diag();
4. Configuration and use
The example assumes that the remote Oracle account APP_USER has the necessary permissions on APP_DATA.REMOTE_ITEMS, with at least ID NUMBER(10), NAME VARCHAR2(100 CHAR), and UPDATED_AT TIMESTAMP(6) columns. Replace the address and credentials with real values.
CREATE SERVER oracle_server
FOREIGN DATA WRAPPER oracle_fdw
OPTIONS (dbserver '//oracle.example:1521/FREEPDB1');
CREATE USER MAPPING FOR CURRENT_USER SERVER oracle_server
OPTIONS (user 'APP_USER', password 'replace-me');
CREATE FOREIGN TABLE remote_items (
id pg_catalog.int4 OPTIONS (key 'true') NOT NULL,
name pg_catalog.text,
updated_at pg_catalog.timestamp
)
SERVER oracle_server
OPTIONS (schema 'APP_DATA', table 'REMOTE_ITEMS');
SELECT id, name FROM remote_items WHERE id > 10;
EXPLAIN VERBOSE SELECT id, name FROM remote_items WHERE id > 10;
BEGIN;
INSERT INTO remote_items (id, name) VALUES (1001, 'example');
UPDATE remote_items SET name = 'updated' WHERE id = 1001;
DELETE FROM remote_items WHERE id = 1001;
ROLLBACK;
Mark columns that belong to the remote primary key with OPTIONS (key 'true') so oracle_fdw can identify rows for UPDATE and DELETE. An IvorySQL role needs USAGE on the foreign server, the relevant foreign-table privileges, and its own user mapping to access remote data. Do not grant these rights or the Oracle credentials to PUBLIC.
5. Oracle mode and limitations
When running the same SQL through the Oracle port, use standard PostgreSQL types supported by oracle_fdw for foreign-table columns, qualifying names with pg_catalog where necessary. In the verified Oracle-mode session, bare timestamp resolved to sys.oratimestamp (OID 9510), which oracle_fdw 2.9.0 cannot convert. Using pg_catalog.timestamp made the query work. This concerns the local foreign-table column type; the remote Oracle table can still use TIMESTAMP(6).
Oracle treats an empty string as NULL; an empty string written through oracle_fdw arrives as NULL remotely. Displaying an Oracle execution plan through EXPLAIN VERBOSE requires the remote account to read V$SQL and V$SQL_PLAN; ordinary reads and writes do not require these privileges. Foreign-table queries fail if OCI or the remote Oracle service is unavailable. To upgrade oracle_fdw, follow its upstream instructions to reinstall the wrapper and run the appropriate ALTER EXTENSION … UPDATE in every database that uses it.