Administración de Sistemas Gestores de Bases de Datos — práctica sobre cómo interconectar servidores de bases de datos para que puedan consultar y modificar datos entre sí: Oracle↔Oracle, PostgreSQL↔PostgreSQL, y la interconexión heterogénea Oracle↔PostgreSQL.
Enlace entre dos servidores Oracle
Un enlace de base de datos (database link) en Oracle permite a un usuario conectarse a una base de datos remota y acceder a sus datos como si estuvieran en la base de datos local, mediante un enlace privado que almacena las credenciales de conexión.
Configuración básica de las máquinas
Dos máquinas Oracle: Oracle1 (192.168.122.222) y Oracle2 (192.168.122.237).
En Oracle1:
1sqlplus / as sysdba
2
3CREATE USER c##josemanuel1 IDENTIFIED BY josemanuel1;
4GRANT CONNECT, RESOURCE TO c##josemanuel1;
5GRANT CREATE SESSION TO c##josemanuel1;
6GRANT CREATE DATABASE LINK TO c##josemanuel1;
7GRANT UNLIMITED TABLESPACE TO c##josemanuel1;
8exit;

En Oracle2:
1sqlplus / as sysdba
2
3CREATE USER c##josemanuel2 IDENTIFIED BY josemanuel2;
4GRANT CONNECT, RESOURCE TO c##josemanuel2;
5GRANT CREATE SESSION TO c##josemanuel2;
6GRANT CREATE DATABASE LINK TO c##josemanuel2;
7GRANT UNLIMITED TABLESPACE TO c##josemanuel2;
8EXIT;


Usuarios comunes vs. locales: en una Container Database (CDB), los usuarios C## son
comunes y existen en toda la CDB; los usuarios sin C## son locales y solo existen en una
Pluggable Database (PDB) concreta. Para crear un usuario en una PDB (sin el prefijo C##) hay
que conectarse a ella primero:
1SHOW PDBS;
2ALTER SESSION SET CONTAINER = ORCLPDB1;
3alter pluggable database orclpdb1 open;
4-- ya se puede crear el usuario sin problema

Configurar listener en ambos servidores
1sudo nano /opt/oracle/product/21c/dbhome_1/network/admin/listener.ora
En Oracle1:
1LISTENER =
2 (DESCRIPTION_LIST =
3 (DESCRIPTION =
4 (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.122.222)(PORT = 1521))
5 )
6 )

En Oracle2 (misma estructura, con su propia IP):
1LISTENER =
2 (DESCRIPTION_LIST =
3 (DESCRIPTION =
4 (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.122.237)(PORT = 1521))
5 )
6 )

Es recomendable que la IP de cada máquina sea estática (o con reserva DHCP) para que el listener no dé conflictos.
Configurar archivo tnsnames.ora
En Oracle1:
1sudo nano /opt/oracle/product/21c/dbhome_1/network/admin/tnsnames.ora
1#Interconexion con oracle2
2oracle2 =
3 (DESCRIPTION =
4 (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.122.237)(PORT = 1521))
5 (CONNECT_DATA =
6 (SERVICE_NAME = ORCLCDB)
7 )
8 )


Esto define un alias de conexión llamado oracle2: en vez de escribir toda la cadena de conexión
cada vez, basta con usar ese nombre.
- oracle2 → nombre del alias que se usará
- HOST → IP del servidor remoto
- PORT → puerto donde escucha el listener
- SERVICE_NAME → nombre del servicio de base de datos (se obtiene con
SELECT * FROM global_name;)
En Oracle2 se configura el mismo archivo pero apuntando a Oracle1.
Para comprobar que ambos se comunican:
1tnsping oracle2 # desde oracle1
2tnsping oracle1 # desde oracle2



Una respuesta de “Realizado correctamente” confirma que el listener remoto está activo y accesible, y que el database link podrá establecerse sin problemas.
Verificación de conexión cruzada:
1-- Desde Oracle1
2sqlplus c##josemanuel2/josemanuel2@oracle2
3
4-- Desde Oracle2
5sqlplus c##josemanuel1/josemanuel1@oracle1


Link Oracle
Creación del link en Oracle1:
1sqlplus c##josemanuel1/josemanuel1
2
3CREATE DATABASE LINK link_oracle2
4CONNECT TO C##josemanuel2 IDENTIFIED BY josemanuel2
5USING 'oracle2';

CREATE DATABASE LINK crea el enlace (link_oracle2 es su nombre); CONNECT TO es el
usuario remoto de Oracle2; USING 'oracle2' es el alias definido en tnsnames.ora.
Verificar el enlace creado:
1SELECT * FROM dba_db_links;

Tabla de ejemplo en Oracle1 para probar el link:
1CREATE TABLE liga_espanola (
2 id NUMBER PRIMARY KEY,
3 equipo VARCHAR2(100) NOT NULL,
4 ciudad VARCHAR2(50),
5 puntos NUMBER DEFAULT 0,
6 partidos_jugados NUMBER DEFAULT 0
7);
8INSERT INTO liga_espanola VALUES (1, 'Sevilla FC', 'Sevilla', 78, 30);
9INSERT INTO liga_espanola VALUES (2, 'Real Madrid', 'Madrid', 75, 30);
10INSERT INTO liga_espanola VALUES (3, 'FC Barcelona', 'Barcelona', 73, 30);
11INSERT INTO liga_espanola VALUES (4, 'Atlético de Madrid', 'Madrid', 70, 30);
12INSERT INTO liga_espanola VALUES (5, 'Real Betis', 'Sevilla', 65, 30);
13INSERT INTO liga_espanola VALUES (6, 'Valencia CF', 'Valencia', 60, 30);
Lo mismo pero al revés (desde Oracle2, para que el enlace sea bidireccional):
1sqlplus c##josemanuel2/josemanuel2
2
3CREATE DATABASE LINK link_oracle1
4CONNECT TO c##josemanuel1 IDENTIFIED BY josemanuel1
5USING 'oracle1';
6
7CREATE TABLE motos (
8 id NUMBER PRIMARY KEY,
9 marca VARCHAR2(100) NOT NULL,
10 modelo VARCHAR2(100),
11 cilindrada NUMBER,
12 precio NUMBER(8,2),
13 tipo VARCHAR2(50)
14);
15INSERT INTO motos VALUES (1, 'Honda', 'CBR 1000RR', 1000, 18500.00, 'Deportiva');
16INSERT INTO motos VALUES (2, 'Yamaha', 'MT-09', 890, 11500.00, 'Naked');
17INSERT INTO motos VALUES (3, 'Kawasaki', 'Ninja ZX-10R', 1000, 22500.00, 'Deportiva');
18INSERT INTO motos VALUES (4, 'Ducati', 'Panigale V4', 1103, 28000.00, 'Deportiva');
19INSERT INTO motos VALUES (5, 'Harley-Davidson', 'Street Glide', 1868, 28500.00, 'Cruiser');
20INSERT INTO motos VALUES (6, 'BMW', 'R 1250 GS', 1254, 19500.00, 'Adventure');
21COMMIT;


Consultas de datos simultáneas
Desde Oracle1 hacia Oracle2:
1SELECT * FROM motos@link_oracle2;

Desde Oracle2 hacia Oracle1:
1SELECT * FROM liga_espanola@link_oracle1;
JOIN combinando datos de ambos servidores en una sola consulta:
1SELECT m.marca, m.modelo, m.precio, e.equipo, e.ciudad, e.puntos
2FROM motos m, liga_espanola@link_oracle1 e
3WHERE m.id = e.id
4ORDER BY m.id;


Errores encontrados (Oracle↔Oracle)
Error de listener (tnsping no funcionaba): tenía otro tnsnames.ora/listener.ora escondido
en otra ruta, generando conflicto. Solución — quedarme con un único fichero por servicio:
1# desde root, borro los que sobran
2rm -r /opt/oracle/homes/OraDBHome21cEE/network/admin/tnsnames.ora
3rm -r /opt/oracle/homes/OraDBHome21cEE/network/admin/listener.ora
Y dejo solo /opt/oracle/product/21c/dbhome_1/network/admin/{listener,tnsnames}.ora. Luego
reinicio el listener:
1sudo -u oracle bash -c 'export ORACLE_HOME=/opt/oracle/product/21c/dbhome_1 && export PATH=$ORACLE_HOME/bin:$PATH && lsnrctl stop'
2sudo -u oracle bash -c 'export ORACLE_HOME=/opt/oracle/product/21c/dbhome_1 && export PATH=$ORACLE_HOME/bin:$PATH && lsnrctl start'
Error 2 — el listener conecta pero al intentar entrar con el usuario dice que no encuentra el
servicio (ORA-12514): el listener está arrancado pero la base de datos no está registrada en él.
1sqlplus / as sysdba
2
3-- en oracle1
4ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.122.221)(PORT=1521))' SCOPE=BOTH;
5ALTER SYSTEM REGISTER;
6EXIT;
7
8-- en oracle2
9ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.122.237)(PORT=1521))' SCOPE=BOTH;
10ALTER SYSTEM REGISTER;
11EXIT;
Se verifica con lsnrctl status: si el servicio ya aparece listado, la conexión funciona.

Enlace entre dos servidores PostgreSQL
A diferencia de Oracle, donde los database links son nativos, PostgreSQL usa una extensión llamada dblink que hay que habilitar explícitamente.
Dos máquinas: Postgre1 (192.168.122.159, base bd1, tabla portatiles) y Postgre2
(192.168.122.237, base bd2, tabla coches). Se asume que PostgreSQL ya acepta conexiones
remotas (configurado en la instalación).
Creación de usuarios y bases de datos
En Postgre1:
1sudo su - postgres
2psql
3
4CREATE DATABASE bd1;
5CREATE USER josemanuel1 WITH PASSWORD 'josemanuel1';
6GRANT ALL PRIVILEGES ON DATABASE bd1 TO josemanuel1;
7\c bd1
8GRANT ALL PRIVILEGES ON SCHEMA public TO josemanuel1;
9ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO josemanuel1;
En Postgre2

En Postgre2, lo mismo con bd2 / josemanuel2.

Verificación de conectividad
1# Desde Postgre1 hacia Postgre2
2psql -h 192.168.122.237 -U josemanuel2 -d bd2
3
4# Desde Postgre2 hacia Postgre1
5psql -h 192.168.122.159 -U josemanuel1 -d bd1


Instalación de la extensión dblink
Solo los superusuarios (postgres) pueden crear links; si se quiere que un usuario normal
también pueda, se le da con ALTER USER josemanuel1 WITH SUPERUSER;.
En Postgre1:
1psql -U josemanuel1 -d bd1
2CREATE EXTENSION dblink;
En Postgre2:
1psql -U josemanuel2 -d bd2
2CREATE EXTENSION dblink;


Creación de las tablas de ejemplo
En Postgre1 — tabla portatiles:
1CREATE TABLE portatiles (
2 id SERIAL PRIMARY KEY,
3 marca VARCHAR(50),
4 modelo VARCHAR(50),
5 ram INT,
6 almacenamiento INT,
7 precio NUMERIC(10,2)
8);
9INSERT INTO portatiles (marca, modelo, ram, almacenamiento, precio) VALUES
10('Lenovo', 'ThinkPad X1 Carbon', 16, 512, 1500.00),
11('HP', 'Pavilion 15', 8, 256, 700.00),
12('Dell', 'XPS 13', 16, 512, 1600.00),
13('Asus', 'ROG Strix', 32, 1024, 2200.00),
14('Apple', 'MacBook Air M2', 16, 512, 1800.00);

En Postgre2 — tabla coches:
1CREATE TABLE coches (
2 id SERIAL PRIMARY KEY,
3 marca VARCHAR(50),
4 modelo VARCHAR(50),
5 año INT,
6 precio NUMERIC(10,2)
7);
8INSERT INTO coches (marca, modelo, año, precio) VALUES
9('Toyota', 'Corolla', 2020, 18000.00),
10('Honda', 'Civic', 2019, 17500.00),
11('Ford', 'Focus', 2018, 15000.00),
12('BMW', 'Serie 3', 2021, 35000.00),
13('Audi', 'A4', 2022, 38000.00);

Funcionamiento del enlace: primera consulta remota
La función dblink sigue esta estructura:
1SELECT *
2FROM dblink(
3 'cadena_de_conexion',
4 'consulta_SQL'
5) AS alias(definicion_de_columnas);
- cadena_de_conexion → host, base de datos, usuario y contraseña del servidor remoto
- consulta_SQL → la consulta a ejecutar en remoto
- alias → nombre temporal para los resultados
- definicion_de_columnas → nombre y tipo de cada columna que devuelve la consulta
Desde Postgre1, consultando la tabla coches de Postgre2:
1SELECT *
2FROM dblink(
3 'host=192.168.122.237 dbname=bd2 user=josemanuel2 password=josemanuel2',
4 'SELECT * FROM coches'
5) AS equipos_remotos(
6 id VARCHAR,
7 marca VARCHAR,
8 modelo VARCHAR,
9 año INT,
10 precio NUMERIC
11);

Consulta JOIN entre bases de datos distribuidas
1SELECT p.marca, p.modelo, p.precio, c.marca, c.modelo, c.precio
2FROM portatiles p
3LEFT JOIN dblink(
4 'host=192.168.122.237 dbname=bd2 user=josemanuel2 password=josemanuel2',
5 'SELECT id, marca, modelo, precio FROM coches'
6) AS c(id INTEGER, marca VARCHAR, modelo VARCHAR, precio NUMERIC)
7ON p.id = c.id
8ORDER BY p.id;
Enlace bidireccional

Enlace bidireccional
Los enlaces con dblink son unidireccionales por sí mismos, así que para tener consultas en ambas direcciones hay que repetir el proceso en el otro sentido. Desde Postgre2 hacia Postgre1:
1SELECT c.marca, c.modelo, c.año, c.precio, p.marca, p.modelo, p.ram, p.almacenamiento
2FROM coches c,
3dblink(
4 'host=192.168.122.159 dbname=bd1 user=josemanuel1 password=josemanuel1',
5 'SELECT id, marca, modelo, ram, almacenamiento FROM portatiles'
6) AS p(id INTEGER, marca VARCHAR, modelo VARCHAR, ram INTEGER, almacenamiento INTEGER)
7WHERE c.id = p.id
8AND p.almacenamiento >= 512
9ORDER BY c.año DESC;


Operaciones de escritura remota

Operaciones de escritura remota
Para INSERT/UPDATE/DELETE (que no devuelven filas) se usa dblink_exec.
Insertar un portátil en Postgre1 desde Postgre2:
1SELECT dblink_exec(
2 'host=192.168.122.159 dbname=bd1 user=josemanuel1 password=josemanuel1',
3 'INSERT INTO portatiles (marca, modelo, ram, almacenamiento, precio)
4 VALUES (''MSI'', ''Katana GF66'', 16, 512, 1200.00)'
5);

Verificar desde el mismo Postgre2:
1SELECT *
2FROM dblink(
3 'host=192.168.122.159 dbname=bd1 user=josemanuel1 password=josemanuel1',
4 'SELECT * FROM portatiles WHERE marca = ''MSI'''
5) AS nuevo_portatil(id INTEGER, marca VARCHAR, modelo VARCHAR, ram INTEGER, almacenamiento INTEGER, precio NUMERIC);

Con esto queda un enlace bidireccional funcionando entre dos servidores PostgreSQL, con consultas combinadas y escritura remota.
Interconexión Oracle ↔ PostgreSQL
Datos de partida:
- Oracle1 → IP
192.168.122.221, usuarioC##josemanuel1, tablaliga_espanola - Postgre1 → IP
192.168.122.159, usuariojosemanuel1, basebd1, tablaportatiles
Parte 1: Oracle → PostgreSQL
Oracle no tiene soporte nativo para PostgreSQL, así que se usa ODBC + Heterogeneous Services (HS): un estándar que actúa de “traductor universal” entre gestores distintos.
1Cliente → Oracle → ODBC → PostgreSQL
Instalar paquetes ODBC en Oracle1:
1sudo apt update && sudo apt install unixodbc odbc-postgresql

unixODBC→ implementación abierta de la API ODBCodbc-postgresql→ driver específico para PostgreSQL
Configurar el driver de PostgreSQL (comprobar antes dónde se instaló, con
ls -l /usr/lib/x86_64-linux-gnu/odbc/; se usa psqlodbcw.so por ser el más moderno):
1sudo nano /etc/odbcinst.ini
1[PostgreSQL]
2Description = PostgreSQL ODBC driver
3Driver = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so
4Setup = /usr/lib/x86_64-linux-gnu/odbc/libodbcpsqlS.so
5FileUsage = 1
**Crear el DSN


Crear el DSN (Data Source Name) — define cómo conectarse a una base concreta:
1sudo nano /etc/odbc.ini
1[POSTGRE1]
2Description = PostgreSQL Database
3Driver = PostgreSQL
4Servername = 192.168.122.159
5Username = josemanuel1
6Password = josemanuel1
7Port = 5432
8Database = bd1

Probar la conexión ODBC antes de tocar Oracle:
1isql POSTGRE1
1SELECT * FROM portatiles;

Configurar Heterogeneous Services (HS es lo que permite a Oracle hablar con bases no-Oracle vía ODBC):
1sudo nano /opt/oracle/product/21c/dbhome_1/hs/admin/initPOSTGRE1.ora
1HS_FDS_CONNECT_INFO = POSTGRE1
2HS_FDS_TRACE_LEVEL = DEBUG
3HS_FDS_SHAREABLE_NAME = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so
4HS_LANGUAGE = AMERICAN_AMERICA.WE8ISO8859P1
5set ODBCINI=/etc/odbc.ini

Configurar el listener de Oracle para que sepa invocar el gateway heterogéneo:
1sudo nano /opt/oracle/product/21c/dbhome_1/network/admin/listener.ora
1#postgre
2SID_LIST_LISTENER=
3 (SID_LIST=
4 (SID_DESC=
5 (GLOBAL_DBNAME=POSTGRE1)
6 (SID_NAME=POSTGRE1)
7 (ORACLE_HOME=/opt/oracle/product/21c/dbhome_1)
8 (PROGRAM=dg4odbc)
9 (ENVS="LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/odbc:/opt/oracle/product/21c/dbhome_1/lib,ODBCINI=/etc/odbc.ini")
10 )
11 )
- **GLOBAL_DBNAME


- GLOBAL_DBNAME / SID_NAME → nombre del servicio (debe coincidir con
tnsnames.ora) - ORACLE_HOME → ruta de instalación de Oracle (crítico que sea correcta)
- PROGRAM →
dg4odbc, el programa gateway para ODBC - ENVS → variables de entorno necesarias (rutas de librerías ODBC y del
odbc.ini)
Configurar tnsnames.ora:
1sudo nano /opt/oracle/product/21c/dbhome_1/network/admin/tnsnames.ora
1#postgres
2POSTGRE1 =
3 (DESCRIPTION=
4 (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.122.221)(PORT=1521))
5 (CONNECT_DATA=(SID=POSTGRE1))
6 (HS=OK)
7 )


Aquí el HOST es la IP del listener de Oracle, no la de PostgreSQL. (HS=OK) marca que es
un servicio heterogéneo.
Reiniciar el listener y comprobar el estado (el status UNKNOWN es normal para servicios
heterogéneos, ya que no son instancias Oracle):
1sudo -u oracle bash -c 'export ORACLE_HOME=/opt/oracle/product/21c/dbhome_1 && export PATH=$ORACLE_HOME/bin:$PATH && lsnrctl stop'
2sudo -u oracle bash -c 'export ORACLE_HOME=/opt/oracle/product/21c/dbhome_1 && export PATH=$ORACLE_HOME/bin:$PATH && lsnrctl start'
3lsnrctl status
Crear el database link en Oracle:

Crear el database link en Oracle:
1sqlplus C##josemanuel1/josemanuel1
2
3CREATE DATABASE LINK link_postgres
4CONNECT TO "josemanuel1" IDENTIFIED BY "josemanuel1"
5USING 'POSTGRE1';


Probar el enlace (el nombre de tabla va entre comillas porque PostgreSQL distingue mayúsculas/minúsculas):
1SELECT * FROM "portatiles"@link_postgres;

Consulta combinando ambos servidores (columnas de Postgre1 entre comillas porque Oracle las trata como case-sensitive a través del enlace):
1SELECT o.EQUIPO, o.CIUDAD, o.PUNTOS, p."marca", p."modelo", p."precio"
2FROM liga_espanola o, "portatiles"@link_postgres p
3WHERE o.ID = p."id"
4ORDER BY o.PUNTOS DESC;


INSERT / UPDATE / DELETE remotos desde Oracle hacia Postgre1:
1-- INSERT
2INSERT INTO "portatiles"@link_postgres ("id", "marca", "modelo", "ram", "almacenamiento", "precio")
3VALUES (7, 'Acer', 'Aspire 5', 8, 512, 650);
4
5-- UPDATE
6UPDATE "portatiles"@link_postgres
7SET "precio" = 1550
8WHERE "marca" = 'Lenovo';
9
10-- DELETE
11DELETE FROM "portatiles"@link_postgres
12WHERE "id" = 7;


Errores de Oracle a Postgres
Al consultar la tabla remota daba ORA-28500 / ORA-02063: line preciendo a LINK_POSTGRES.
Causa: conflicto de rutas ORACLE_HOME — Oracle buscaba initPOSTGRE1.ora en
/opt/oracle/homes/OraDBHome21cEE/hs/admin/ cuando en realidad estaba creado en
/opt/oracle/product/21c/dbhome_1/hs/admin/.
Solución: usar una única ruta consistente para toda la configuración
(/opt/oracle/product/21c/dbhome_1)

Solución: usar una única ruta consistente para toda la configuración
(/opt/oracle/product/21c/dbhome_1) y asegurarse de que el listener.ora tiene bien las
variables LD_LIBRARY_PATH y ODBCINI. Si el listener no encuentra el ejecutable dg4odbc:
1ls -l /opt/oracle/product/21c/dbhome_1/bin/dg4odbc
2sudo find /opt/oracle -name "dg4odbc"


y se ajusta el ORACLE_HOME del listener.ora a la ruta correcta que devuelva ese comando.
Parte 2: PostgreSQL → Oracle
PostgreSQL tampoco tiene soporte nativo para Oracle, así que se usa oracle_fdw (Foreign Data Wrapper), que necesita el Oracle Instant Client instalado en la máquina PostgreSQL.
1Cliente → PostgreSQL → oracle_fdw → Oracle
Paquetes necesarios en Postgre1:
1sudo apt update && sudo apt install libaio1t64 postgresql-server-dev-all build-essential git unzip wget


libaio1t64→ E/S asíncrona que necesita Oraclepostgresql-server-dev-all→ herramientas de desarrollo para extensiones de PostgreSQLbuild-essential,git,unzip,wget→ compilar y descargar
Descargar Oracle Instant Client (como usuario postgres):
1sudo su - postgres
2
3wget https://download.oracle.com/otn_software/linux/instantclient/211000/instantclient-basic-linux.x64-21.1.0.0.0.zip
4wget https://download.oracle.com/otn_software/linux/instantclient/211000/instantclient-sdk-linux.x64-21.1.0.0.0.zip
5wget https://download.oracle.com/otn_software/linux/instantclient/211000/instantclient-sqlplus-linux.x64-21.1.0.0.0.zip
6
7unzip instantclient-basic-linux.x64-21.1.0.0.0.zip
8unzip instantclient-sqlplus-linux.x64-21.1.0.0.0.zip
9unzip instantclient-sdk-linux.x64-21.1.0.0.0.zip
10rm *.zip


Variables de entorno:
1sudo nano .bashrc
1export ORACLE_HOME=/var/lib/postgresql/instantclient_21_1
2export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME
3export PATH=$PATH:$ORACLE_HOME



1source .bashrc
2which sqlplus


Verificación de conectividad con Oracle. En Debian 13, sqlplus busca libaio.so.1 (nombre
del paquete en Debian 12), pero el sistema tiene libaio.so.1t64 — hace falta un enlace
simbólico:
1sudo ln -s /lib/x86_64-linux-gnu/libaio.so.1t64 /lib/x86_64-linux-gnu/libaio.so.1
2sudo ldconfig
1sqlplus c##josemanuel1/josemanuel1@192.168.122.221/ORCLCDB
2select * from liga_espanola;
3exit;

Compilar e instalar oracle_fdw:
1cd /var/lib/postgresql
2git clone https://github.com/laurenz/oracle_fdw.git
3cd oracle_fdw
4sudo make ORACLE_HOME=/var/lib/postgresql/instantclient_21_1
5sudo make install

Librerías compartidas:
1echo '/var/lib/postgresql/instantclient_21_1' | sudo tee /etc/ld.so.conf.d/oracle.conf
2sudo ldconfig
Creación del enlace en PostgreSQL:
1psql -U josemanuel1 -d bd1
2CREATE EXTENSION oracle_fdw;
3\dx
Esquema para las tablas remotas y definición del servidor:
1CREATE SCHEMA oracle_schema;
2
3CREATE SERVER servidor_oracle1
4FOREIGN DATA WRAPPER oracle_fdw
5OPTIONS (dbserver '//192.168.122.221/ORCLCDB');


Mapeo de usuarios y permisos:
1CREATE USER MAPPING FOR josemanuel1
2SERVER servidor_oracle1
3OPTIONS (user 'c##josemanuel1', password 'josemanuel1');
4
5GRANT ALL PRIVILEGES ON SCHEMA oracle_schema TO josemanuel1;
6GRANT ALL PRIVILEGES ON FOREIGN SERVER servidor_oracle1 TO josemanuel1;
Importar las tablas remotas (el esquema de Oracle va en MAYÚSCULAS y entre comillas, porque Oracle almacena los nombres así por defecto):
1IMPORT FOREIGN SCHEMA "C##JOSEMANUEL1"
2FROM SERVER servidor_oracle1
3INTO oracle_schema;
4
5\det oracle_schema.*
Consultar datos combinados. El nombre de tabla mantiene el formato Oracle y va entre
comillas ("liga_espanola"), pero los nombres de columna se convierten a minúsculas y no
llevan comillas:
1SELECT p.id, p.marca, p.modelo, p.precio, o.equipo, o.ciudad, o.puntos
2FROM portatiles p
3LEFT JOIN oracle_schema."liga_espanola" o ON p.id = o.id
4ORDER BY p.id;
INSERT / UPDATE / DELETE remotos desde PostgreSQL hacia Oracle:
1-- INSERT
2INSERT INTO oracle_schema."liga_espanola" (id, equipo, ciudad, puntos, partidos_jugados)
3VALUES (7, 'Real Sociedad', 'San Sebastián', 58, 30);
4
5-- UPDATE
6UPDATE oracle_schema."liga_espanola"
7SET puntos = 80, partidos_jugados = 31
8WHERE equipo = 'Real Madrid';
9
10-- DELETE
11DELETE FROM oracle_schema."liga_espanola"
12WHERE id = 7;
Conclusión
Con esto quedan cubiertos los tres escenarios de interconexión: Oracle↔Oracle (nativo, vía database links), PostgreSQL↔PostgreSQL (vía la extensión dblink) y la interconexión heterogénea Oracle↔PostgreSQL en ambos sentidos (ODBC + Heterogeneous Services para Oracle→Postgres, y oracle_fdw para Postgres→Oracle). En los tres casos se pueden hacer tanto consultas combinadas (JOIN entre servidores) como operaciones de escritura remota.
