Skip to content

ORA-02064: Distributed Operation Not Supported - Workarounds

ORA-02064: Distributed Operation Not Supported

Section titled “ORA-02064: Distributed Operation Not Supported”

Error Text: ORA-02064: distributed operation not supported

The ORA-02064 error is raised when an application attempts an operation over a database link that Oracle’s distributed execution engine cannot perform. Unlike ORA-02055, which signals a failure mid-transaction, ORA-02064 is raised immediately — Oracle detects the unsupported pattern before attempting execution and rejects it outright.

The error most commonly appears when developers attempt DDL statements over a database link, use Oracle sequences remotely in unsupported contexts, manipulate LOB columns through a link, or try to call certain PL/SQL constructs remotely. Understanding which operations are prohibited and applying the correct workaround pattern is the key to resolving this error without a full architectural change.

  • CREATE TABLE, DROP TABLE, ALTER TABLE cannot be executed remotely via a database link
  • CREATE INDEX, GRANT, REVOKE and other DDL are likewise blocked
  • Oracle’s distributed SQL engine only supports DML (INSERT, UPDATE, DELETE, SELECT) over links

2. Remote Sequence Access in Unsupported Contexts

Section titled “2. Remote Sequence Access in Unsupported Contexts”
  • SELECT seq.NEXTVAL FROM dual@remote_link is not supported in all versions and contexts
  • Using a remote sequence inside a trigger or PL/SQL block that also contains local DML
  • Referencing a remote sequence in a subquery used for INSERT
Section titled “3. LOB Column Operations Over Database Links”
  • SELECT of a CLOB or BLOB column directly over a database link is restricted in older versions
  • UPDATE of a LOB column remotely is not supported without special handling
  • BFILE operations are always local and cannot traverse a database link
  • EXECUTE IMMEDIATE targeting a remote database directly
  • Calling remote stored procedures that themselves perform DDL
  • Using DBMS_SQL across a database link
  • Attempting Oracle-specific syntax against a non-Oracle database via a gateway
  • Using Oracle-only functions (DECODE, CONNECT BY, etc.) in a pass-through context that the gateway cannot translate
  • Attempting DML with RETURNING clause over a heterogeneous link
  • Using SAVEPOINT followed by a distributed DML within the same transaction in certain configurations
  • Attempting LOCK TABLE over a database link
  • Running SELECT FOR UPDATE across a link when the remote side cannot support it
-- Find the SQL that caused ORA-02064 in the current session
SELECT
sql_id,
sql_text,
executions,
last_active_time,
parsing_schema_name
FROM v$sql
WHERE sql_text LIKE '%@%' -- Contains DB link reference
AND last_active_time > SYSDATE - 1/24
ORDER BY last_active_time DESC
FETCH FIRST 20 ROWS ONLY;
-- Review all database links to understand remote targets
SELECT
owner,
db_link,
username,
host,
created
FROM dba_db_links
ORDER BY owner, db_link;
-- Check for heterogeneous (non-Oracle) links
SELECT
db_link,
username,
host
FROM dba_db_links
WHERE UPPER(host) LIKE '%HS%'
OR UPPER(host) LIKE '%GATEWAY%'
OR UPPER(host) LIKE '%ODBC%'
OR UPPER(host) LIKE '%JDBC%';
-- Query the data dictionary of the remote database to confirm it is Oracle
SELECT banner FROM v$version@remote_db_link;
-- Check which Oracle version the remote database is running
SELECT
version,
version_full
FROM v$instance@remote_db_link;
-- Find LOB columns in the remote table causing the error
SELECT
column_name,
data_type,
data_length
FROM all_tab_columns@remote_db_link
WHERE table_name = UPPER('target_table')
AND data_type IN ('CLOB', 'BLOB', 'NCLOB', 'BFILE', 'XMLTYPE')
ORDER BY column_id;
-- Check alert log for ORA-02064 occurrences
SELECT
originating_timestamp,
message_text
FROM v$diag_alert_ext
WHERE message_text LIKE '%ORA-02064%'
ORDER BY originating_timestamp DESC
FETCH FIRST 30 ROWS ONLY;

Check Supported Remote Operations (Heterogeneous Services)

Section titled “Check Supported Remote Operations (Heterogeneous Services)”
-- For heterogeneous links, view capabilities of the remote database
SELECT
capability_name,
capability_description,
is_supported,
is_updateable
FROM v$hs_capability@remote_non_oracle_link
ORDER BY capability_name;

1. Identify the Exact Unsupported Operation

Section titled “1. Identify the Exact Unsupported Operation”

Carefully examine the SQL or PL/SQL that raised ORA-02064 and determine which category of restriction applies. Common categories and their solutions:

Operation Attempted RemotelySupported via DB Link?Workaround
SELECT (non-LOB)YesNone needed
INSERT / UPDATE / DELETEYesNone needed
DDL (CREATE, ALTER, DROP)NoUse remote procedure
LOB SELECT (12c+)PartiallyUse remote function
SEQUENCE.NEXTVALLimitedUse remote procedure
EXECUTE IMMEDIATENoUse remote procedure
LOCK TABLENoRestructure transaction
Section titled “2. Workaround for DDL Over a Database Link”

DDL cannot be sent directly over a link. Create a stored procedure on the remote database that performs the DDL, then call it through the link:

-- On the REMOTE database: create a wrapper procedure
CREATE OR REPLACE PROCEDURE remote_create_table(
p_table_name IN VARCHAR2,
p_ddl_suffix IN VARCHAR2
) AS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE ' || DBMS_ASSERT.SIMPLE_SQL_NAME(p_table_name)
|| ' (' || p_ddl_suffix || ')';
END;
/
-- On the LOCAL database: call the remote procedure through the link
BEGIN
remote_create_table@remote_db_link('STAGING_TABLE', 'id NUMBER, col1 VARCHAR2(100)');
END;
/
Section titled “3. Workaround for Sequences Over a Database Link”

Use a remote function that wraps the sequence call:

-- On the REMOTE database: create a function to vend sequence values
CREATE OR REPLACE FUNCTION get_next_seq_val RETURN NUMBER AS
BEGIN
RETURN remote_sequence.NEXTVAL;
END;
/
-- On the LOCAL database: call the function through the link
DECLARE
v_next_id NUMBER;
BEGIN
v_next_id := get_next_seq_val@remote_db_link();
INSERT INTO local_table (id, col1) VALUES (v_next_id, 'value');
COMMIT;
END;
/
Section titled “4. Workaround for LOB Columns Over a Database Link”

For LOB data, retrieve it using a remote function that converts the LOB to VARCHAR2 chunks or uses a staging approach:

-- For small CLOBs: cast to VARCHAR2 in a remote view or function
CREATE OR REPLACE FUNCTION get_clob_as_varchar(p_id IN NUMBER)
RETURN VARCHAR2
AS
v_clob_text CLOB;
v_result VARCHAR2(32767);
BEGIN
SELECT clob_column INTO v_clob_text
FROM remote_table
WHERE id = p_id;
v_result := SUBSTR(TO_CHAR(v_clob_text), 1, 32767);
RETURN v_result;
END;
/
-- Call remotely
SELECT get_clob_as_varchar@remote_db_link(42) FROM dual;

For large LOBs, use a staging table approach:

-- Stage data locally first, then process
INSERT INTO local_staging (id, varchar_chunk)
SELECT id, SUBSTR(clob_col, 1, 4000)
FROM remote_table@remote_db_link
WHERE id = :target_id;
COMMIT;

5. Workaround Using Remote Stored Procedures for Complex Operations

Section titled “5. Workaround Using Remote Stored Procedures for Complex Operations”

Encapsulate all unsupported operations in a remote stored procedure:

-- On the REMOTE database
CREATE OR REPLACE PROCEDURE process_remote_batch(
p_batch_id IN NUMBER,
p_status OUT VARCHAR2
) AS
BEGIN
-- All DDL, sequence usage, LOB operations happen locally on remote DB
INSERT INTO batch_log (batch_id, processed_at) VALUES (p_batch_id, SYSDATE);
COMMIT;
p_status := 'SUCCESS';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
p_status := 'ERROR: ' || SQLERRM;
END;
/
-- On the LOCAL database: invoke it through the link
DECLARE
v_status VARCHAR2(200);
BEGIN
process_remote_batch@remote_db_link(1001, v_status);
DBMS_OUTPUT.PUT_LINE('Remote result: ' || v_status);
END;
/
Section titled “6. Workaround for Heterogeneous (Non-Oracle) Database Links”

For non-Oracle databases, use passthrough SQL via the DBMS_HS_PASSTHROUGH package:

-- Execute passthrough SQL against a non-Oracle remote database
DECLARE
v_cursor INTEGER;
v_rows INTEGER;
BEGIN
v_cursor := DBMS_HS_PASSTHROUGH.OPEN_CURSOR@remote_non_oracle_link;
DBMS_HS_PASSTHROUGH.PARSE@remote_non_oracle_link(
v_cursor,
'CREATE TABLE staging_table (id INT, col1 VARCHAR(100))'
);
v_rows := DBMS_HS_PASSTHROUGH.EXECUTE_NON_QUERY@remote_non_oracle_link(v_cursor);
DBMS_HS_PASSTHROUGH.CLOSE_CURSOR@remote_non_oracle_link(v_cursor);
END;
/

1. Audit Remote Operations Before Deployment

Section titled “1. Audit Remote Operations Before Deployment”

Before deploying code that uses database links, review every statement for unsupported patterns:

-- Find all SQL in the library cache that uses DB links
SELECT
sql_id,
SUBSTR(sql_text, 1, 200) as sql_snippet,
executions,
last_active_time
FROM v$sql
WHERE sql_text LIKE '%@%'
AND (
UPPER(sql_text) LIKE 'CREATE%'
OR UPPER(sql_text) LIKE 'ALTER%'
OR UPPER(sql_text) LIKE 'DROP%'
OR UPPER(sql_text) LIKE 'EXECUTE%'
)
ORDER BY last_active_time DESC;

2. Encapsulate All Remote Operations in PL/SQL Packages

Section titled “2. Encapsulate All Remote Operations in PL/SQL Packages”

Create a dedicated package on the remote database for every operation the local database needs to invoke. This eliminates ad-hoc DB-link SQL and makes the interface explicit and maintainable:

-- Remote database: remote_ops package
CREATE OR REPLACE PACKAGE remote_ops AS
PROCEDURE insert_record(p_id IN NUMBER, p_val IN VARCHAR2);
PROCEDURE delete_record(p_id IN NUMBER);
FUNCTION get_status(p_id IN NUMBER) RETURN VARCHAR2;
END;
/

3. Test Against Remote Database Type and Version

Section titled “3. Test Against Remote Database Type and Version”

Always test operations against the actual remote database type (Oracle vs non-Oracle) and version during development. Capabilities differ across versions and gateway configurations:

-- Confirm the remote target is Oracle before assuming full SQL support
SELECT banner FROM v$version@remote_db_link;

4. Use Views on the Remote Database to Abstract LOB Complexity

Section titled “4. Use Views on the Remote Database to Abstract LOB Complexity”
-- On the REMOTE database: create a view that converts LOBs to VARCHAR2
CREATE OR REPLACE VIEW v_remote_data_no_lob AS
SELECT
id,
name,
SUBSTR(description_clob, 1, 4000) AS description_varchar,
created_at
FROM remote_data_table;
-- SELECT from the view over the link (no LOB restriction)
SELECT * FROM v_remote_data_no_lob@remote_db_link WHERE id = :id;

These Oracle Day by Day utility scripts are relevant to diagnosing distributed operation issues:

  • gvsess.sql — Session-level diagnostics for active distributed operations
  • ORA-02055 - Distributed update failed; rollback required
  • ORA-02063 - Preceding line from database link
  • ORA-02067 - Transaction or savepoint rollback required
  • ORA-02069 - GLOBAL_NAMES parameter must be TRUE
  • ORA-02070 - Database does not support operation in this context
  • ORA-02049 - Timeout: distributed transaction waiting for lock
  1. Identify the unsupported operation and stop the failing call

    -- Kill the session issuing the unsupported operation
    ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
  2. Verify the database link target is reachable and is Oracle

    SELECT banner FROM v$version@remote_db_link;
  3. Wrap the unsupported operation in a remote stored procedure immediately

    -- Quick temporary wrapper on the remote database
    CREATE OR REPLACE PROCEDURE temp_remote_ddl AS
    BEGIN
    EXECUTE IMMEDIATE 'ALTER TABLE target_table ADD (new_col VARCHAR2(100))';
    END;
    /
    -- Call from local:
    EXECUTE temp_remote_ddl@remote_db_link;
-- Verify no lingering in-doubt transactions from the failed attempt
SELECT COUNT(*) FROM dba_2pc_pending;
-- Confirm the link is fully operational after workaround is in place
SELECT SYSDATE FROM dual@remote_db_link;
-- Document the remote capability boundary for the team
SELECT
db_link,
username,
host
FROM dba_db_links
WHERE db_link = 'REMOTE_DB_LINK';