Thanks to everyone who tried to help. This turned out to be a limitation of Oracle:
The information in this article applies to the following products.
PL / SQL - Version 9.2.0.8 and later. The information in this document applies to any platform. Checked for relevance 01-Apr-2015
Problem
The PL / SQL block fails with an error: ORA-00980: synonym translation no longer duration when selecting data from a remote database. The following code demonstrates this problem:
In DB3 (create table)
CONNECT u3 / u3 tab DROP TABLE; CREATE TABLE tab (number c1); INSERT INTO VALUES tab (1); COMMIT;
In DB2 (create a synonym for tables in DB3)
CONNECT u2 / u2 DROB DATABASE LINK dblink2; CREATE DATABASE dblink2 CONNECT TO u3 IDENTIFIED u3 USE 'EMT102U6'; SELECT * FROM global_name @ dblink2; DROP SYNONYM syn2; CREATE SYNONYM syn2 FOR tab @ dblink2; SELECT * FROM syn2;
In DB1 (create a synonym for DB2)
CONNECT u1 / u1 DROB DATABASE LINK dblink1; CREATE DATABASE dblink1 CONNECT TO u2 IDENTIFIED u2 USE 'EMT102W6'; SELECT * FROM global_name @ dblink1; DROP SYNONYM syn1; CREATE SYNONYM syn1 FOR syn2 @ dblink1; SELECT c1 from syn1;
This works in SQL, but it fails when calling from PL / SQL
DECLARE num NUMBER; BEGIN SELECT c1 INTO num FROM syn1; END; /
ERROR on row 4: ORA-06550: row 4, column 3: PL / SQL: ORA-00980: synonym for translation is no longer valid ORA-06550: row 4, column 3: PL / SQL: SQL expression is ignored
CAUSE
This issue was reported in Bug 2829591 QUERING FROM A PL / SQL PROCEDURE IN 9I → 8I-> 7.3.4, OBTAINING OPA-980. This error was closed as "NOT BUG" for the following reasons.
PL / SQL cannot instruct the secondary database (DB2) to keep track of the database link at compile time. Therefore, for this PL / SQL block to compile and run, both database links dblink1 and dblink2 must be defined in the foreground database - DB1. During operation, a link to the dblink2 database will search in DB2 as expected.
DECISION
To implement the solution, follow these steps:
- Create dblink2 database link in DB1, pointing to DB3
SQL> create a link to the dblink2 database connect to u3 identified by u3 using 'EMT102U6';
- Create and compile a PL / SQL block in DB1.
CREATE DATABASE LINK dblink2 CONNECT to u3 IDENTIFIED u3 USE 'EMT102U6';
SELECT * FROM global_name @ dblink2; DECLARE num NUMBER; TO BEGIN
SELECT c1 INTO num FROM syn1; END; / PL / SQL completed successfully.
TIP. Another option is to use dyanmic SQL in the PL / SQL block how to work around. When using dynamic SQL, a database reference is not resolved at compile time, but at run time.