Pages

Showing posts with label DBLink. Show all posts
Showing posts with label DBLink. Show all posts

Wednesday, June 28, 2017

"ORA-00900: invalid SQL statement" and "ORA-02064 Distributed operation not supported" Errors When calling to Remote PL/SQL Procedure

================================
General
================================
A. When calling to a remote PL/SQL procedure from sqlplus - all works fine,
But when calling to the same remote PL/SQL procedure from PL/SQL code, an ORA-00900: invalid SQL statement error is thrown.

B. When calling a PL/SQL directly, all works fine, but when calling same procedure vi db link, it fails with ORA-02064 Distributed operation not supported

Why is that?

================================
ORA-00900 Example
================================
In this example, a DB_LINK named KUKU is created to the remote database.

CREATE DATABASE LINK KUKU CONNECT TO REMOTE_USER IDENTIFIED BY REMOTE_PASSWORD USING 'REMOTE_HOST_NAME';

In the remote database, a getDate Procedure in Package PKG_TEST should be activated.

In sqlplus
From sqlplus, any of these versions work:
EXEC PKG_TEST.getDate@KUKU;
EXEC REMOTE_USER.PKG_TEST.getDate@KUKU;

When creating a Synonym, it can be also used, to simplify code.

CREATE SYNONYM REMOTE_PKG FOR REMOTE_USER.PKG_TEST@KUKU

SELECT * FROM USER_SYNONYMS WHERE synonym_name = 'KUKU'

SYNONYM_NAME        TABLE_OWNER      TABLE_NAME      DB_LINK
------------------- ---------------- --------------- ---------------
REMOTE_PKG          REMOTE_USER      PKG_TEST        KUKU

So in sqlplus, it would be:
EXEC REMOTE_PKG.getDate;

In PL/SQL
When activating the same code in PL/SQL it MUST be inside a BEGIN END block.
Any other syntax, such as EXECUTE IMMEDIATE <sql_string> would fail with "ORA-00900: invalid SQL statement".

This is the correct code:

BEGIN
  PKG_TEST.getDate;
  EXCEPTION
    WHEN OTHERS THEN
      WRITE_LOG(v_module_name,'Error Running: '||v_sql_str||' '||SQLERRM);
      RAISE;
END;


================================
ORA-02064 Example
================================
In this example, same DB_LINK named KUKU is created to the remote database.
The procedure now is a DML Procedre, performing an update, and a commit.

The remote procedure has these API:

PKG_TEST.setDate(v_date    IN DATE,

                v_result  OUT NUMBER);

When calling the remote procedure in PL/SQL, it would be:


DECLARE
  v_date   DATE;
  v_result NUMBER;
BEGIN
  v_date := SYSDATE;
  PKG_TEST.setDate(v_date,v_result);
  EXCEPTION
    WHEN OTHERS THEN
      WRITE_LOG(v_module_name,'Error Running: '||v_sql_str||' '||SQLERRM);
      RAISE;


END;


The returned error is:

ORA-02064: distributed operation not supported
ORA-06512: at "REMOTE_USER.PKG_TEST", line 491

Per Oracle documentation, 

Error Cause:
One of the following unsupported operations was attempted:

1. array execute of a remote update with a subquery that references a dblink, or

2. an update of a long column with bind variable and an update of a second column with a subquery that both references a dblink and a bind variable, or

3. a commit is issued in a coordinated session from an RPC procedure call with OUT parameters or function call.

Action:
Simplify remote update statement.

Per Oracle Metalink CALLING REMOTE PACKAGE RECEIVES ORA-2064 (Doc ID 1026597.6):
"This is Not A Bug. 
In the documentation for ORA-2064, it states that one of  the disallowed actions is "A commit is issued in a coordinated session from an RPC with OUT parameters." 
It happens that the return value of a function call counts as an OUT parameter for purposes of this rule. 

As a workaround for some cases Pragma AUTONOMOUS_TRANSACTION can be used in the called function or procedure in the remote site package."


So, a work around this problem would be to change the remote Procedure to be Autonomous Transaction.

PKG_TEST.setDate(v_date    IN DATE,
                v_result  OUT NUMBER) IS
PRAGMA AUTONOMOUS_TRANSACTION;


Sunday, July 19, 2015

DB_LINKS by Example

===============================
General
===============================
DB_LINKS by Example.
Some notes, example, troubleshooting.

===============================
DB_LINKS related tables
===============================
DBA_DB_LINKS and  V$DBLINK

DBA_DB_LINKS lists all defined db_links in the Instance.
V$DBLINK lists currently open db_links by the session.
You cannot query V$DBLINK for other sessions, even as privileged user!!!

V$DBLINK columns
db_link        Db link name
owner_id       Owner name
logged_on      Is the database link currently logged on
protocol       Dblink's communications protocol
open_cursors   Are there any cursors open for the db link 
in_transaction Is the db link part of an open transaction which 
update_sent    Was there an update on the db link 

===============================
How to control the number of DB Links:
===============================
SELECT name, value from V$PARAMETER WHERE name like '%link%';
NAME                           VALUE
------------------------------ ------------------------------
open_links                     12
open_links_per_instance        4

OPEN_LINKS is a static parameter, it cannot be modified in run time.

ALTER SYSTEM SET OPEN_LINKS=10 SCOPE=BOTH;
ALTER SYSTEM SET OPEN_LINKS=10 SCOPE=BOTH
                 *
ERROR at line 1:
ORA-02095: specified initialization parameter 
cannot be modified

ALTER SYSTEM SET OPEN_LINKS=10 SCOPE=SPFILE;
System altered.

===============================
ORA-02020: too many database links
===============================
If number of open DB_LINKS exceeds the limit set by open_links,exception is thrown:
ORA-02020: too many database links in use

===============================
Closing a DB_LINK.
===============================
Per Oracle documentation:
"If you access a database link in a session, then the link remains open until you close the session. 
A link is open in the sense that a process is active on each of the remote databases accessed through the link."

The only way to forcefully close a database link is to issue commit, even if the session does not perform any DML operations, and then, optionally, explicitly close DB_LINK with ALTER SESSION CLOSE DATABASE LINK.

commit;
ALTER SESSION CLOSE DATABASE LINK <link_name>;

This is equivalent to using DBMS_SESSION.CLOSE_DATABASE_LINK.


BEGIN
   commit;
   DBMS_SESSION.CLOSE_DATABASE_LINK('link_name');
END;

===============================
Connection via DBLink Hangs
===============================
When connecting via db link - the connection hangs
When connecting via sqlplus - all is well
-?

Per Oracle technote, might need to increase SDU size:
SQL Hangs When Using Database Link (Doc ID 551117.1)

SDU stands for Session Data Unit - and is a controls the Session OSI layer buffers size.
SDU is the Session Data Unit of the NS layer and regulates the size of the sent and read data to the NT layer. 

Default value is 2048 bytes.
To override value, set (SDU=8192) in tnsnames.ora
The possible value, should be a multiplyer of 2048 (2048, 4096,8196...)

ARM_ARTEL_IPN =(DESCRIPTION = (SDU=8192)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST = 100.200.300.400)(PORT = 1521)))(CONNECT_DATA=(SERVICE_NAME = igt)))



===============================
Reference
===============================
Nice reference with examples. Link
Tom Kyte post on DB_LINKS. Link
Oracle Reference. Link



Tuesday, November 18, 2014

DBLINKs in Oracle Streams Environment

DB LINKs in Oracle Streams Environment

When working in Oracle Streams Environment, the parameter GLOBAL_NAMES must be set to TRUE.

SELECT * FROM GLOBAL_NAME;
GLOBAL_NAME
-----------
ORADB1


SELECT name, value 
FROM V$PARAMETER WHERE name like '%global%';
NAME            VALUE
--------------- ----------
global_names    TRUE

Limitation for naming the database link
When GLOBAL_NAMES is set to true, the name of the DBLINK must be the same as the name of the database!

Per Oracle documentation, the name of the database link should match the global name of the target database if GLOBAL_NAMES=TRUE. 

This seems to be very restricting since then there can be only one database link per schema to a given database, if global_names is set to true. 
To overcome this limitation need to use database link qualifiers. 

Database Link Qualifiers
The syntax is: dblink@dbqualifier

For example: 
CREATE DATABASE LINK oradb1@link1 USING 'conn_str1'; 
CREATE DATABASE LINK oradb1@link2 USING 'conn_str2'; 

And the application, should use below code:
SELECT SYSDATE FROM DUAL@oradb1@link1;

To make the code more robust, create SYNONYMS for the remote objects, and have the application use the synonym name.

CREATE SYNONYM TABLE_1 FOR TABLE_1@oradb1@link1;
CREATE SYNONYM TABLE_2 FOR TABLE_2@oradb1@link2;

ORA-02085
What happens if you create a database link with name other than  the value of GLOBAL_NAME?
You get ORA-02085 - database link string connects to string
Cause:  A database link connected to a database with a different name. 
              The connection is rejected.
Action: Create a database link with the same name as the database it connects to, 
               or set global_names=false.