Skip to Main Content
  • Questions
  • Call a stored procedure over a database link

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Pierre.

Asked: June 28, 2000 - 1:47 am UTC

Last updated: April 22, 2013 - 12:50 pm UTC

Version: 7.3.2.3

Viewed 50K+ times! This question is

You Asked

!!!!
!!2000-07-05 THIS HAS BEEN UPDATED AS PER REQUEST, SEE BELOW!!
!!!!
!!!!
!!2000-06-30 THIS HAS BEEN UPDATED AS PER REQUEST, SEE BELOW!!
!!!!
We have developed a stored procedure in one of our machines. How can I run this procedure from another machine (or other database instance).

I am familar with database links and synonyms. I have set up a database link accessing the machine as the correct user (owning the procedure). I can run "select * from table1@machine1" and that works OK. I try to do a smilar thing with my procedure "execute proc1@machine1". No luck, it does not like the '@' sign. I try to create a synonym for the procedure but still no luck.

Can I run a stored procedure on a foreign machine?
How? What is the syntax?
Do I need to make it "public"?

Thanks!

Best regards
Pierre Oberg

Update, 2000-06-30.
These are the errors that I get:
SQL> execute put_ai@as69('TESTAIC1',33)
begin put_ai@as69('TESTAIC1',33); end;

*
ERROR at line 1:
ORA-02074: cannot ROLLBACK in a distributed transaction
ORA-06512: at "GTADMIN.GT", line 245
ORA-06512: at "GTADMIN.GT", line 1393
ORA-06512: at "GTADMIN.GTAI", line 254
ORA-06512: at "OPS$OCSMGR.PUT_AI", line 7
ORA-02041: client database did not begin a transaction
ORA-02041: client database did not begin a transaction
ORA-06512: at line 1


The put_ai is a procedure that I have written and it looks like:
CREATE OR REPLACE PROCEDURE PUT_AI (tag VARCHAR2,value NUMBER)
IS
BEGIN

DECLARE
status GT.AccessStatus;

BEGIN
IF gtAI.put_VALUE(tag,value,status) != GT.SUCCESS THEN
DBMS_OUTPUT.PUT_LINE('Function failed');
ELSE
DBMS_OUTPUT.PUT_LINE('Access status code = ' || status.codes);
END IF;
END;
END PUT_AI;
/

commit;


The gtAI is part of our "operating environment". It is itself a stored procedure and part of a package.

So, it looks like the problem is in in its implementation. Any ideas how to get around this?
Is the gtAI our problem?
From the error messages above, can you draw any conclusions?


Thanks!

/Pierre Oberg


Update, 2000-07-05.

Hello Tom,

a little bit of background first:
Our Historian system where this Oracle database resides, sits on top of what is called a DCS (Distibuted Control System). Features in this system allow us to read and write values to and from real objects in this DCS.

This gtAI.put_VALUE mentioned above, works fine when you are in the local node.

I have tried to look into this and yes, it this package GT is calling both ROLLBACK and COMMIT. It is actually inserting values into a table from where the data is being put into our objects. After the insert,a commit is issued. I'd say that this commit is needed.

So, how come we have a probelm with commit and rollback when we are calling this proceudre from a external node?

Please let me know if you need info.
Please also let me know if there is anything that can be done to fix this (based on that we need commit and rollback in our base package). Is there anything we can do?

Best regards
Pierre Oberg





and Tom said...

In a distribute transaction -- one in which "DATABASE A" calls "DATABASE B", only "DATABASE A" may commit -- the reason -- "database B" has no mechanism for co-ordinating with "database a" on the commit. We need to do a 2 phase commit to ensure that when the transaction commits any work performed on DATABASE A is committed *as well as* any work on database b.


The problem becomes more complex in general when database a calls both database b and database c. Here, if database b (which has NO IDEA that database c is even involved) attempted to commit -- it would not be able to coordinate with database a and having no knowledge of the existence of database c in the transaction -- could not coordinate it either.

This is the reason will do no allow for ANY node other then the "parent" node of the transaction to issue a commit or rollback in a distributed transaction. The other nodes simply do not have control over the other possible nodes in the transaction.

It is never *needed* that you commit within the stored procedure (in fact, when I program -- i explicitly outlaw the use of commit or rollback in a procedure/function unless you are using autonomous transactions (new in 8i -- see
</code> http://asktom.oracle.com/~tkyte/autonomous/index.html <code>
for a discussion)

It should always be left to the CALLER as to whether they need to commit or rollback. The problem with procedures committing is that at some point in the future, you will need to call 2 or 3 of these procedures as a single transaction (new functionality). All (or none) should succeed (or fail). If one or more them "commits" or rollsback for you -- you cannot achieve this. I hate commits in procedures -- they totally mess everything up and its very hard to program correct transactions once you start putting them in there.

The only thing I can suggest to you now is to add a new optional parameter to the existing routine -- a commit flag (make it be something like:
....
p_do_not_commit boolean in default FALSE );
....

You will then seek out all commit and rollback statements in the affected routine and rewrite them as:

if ( NOT p_do_not_commit ) then
commit;
end if;


When you call this routine you will pass:

....
p_do_not_commit => TRUE );

as the last parameter. Since you are adding a DEFAULTED (optional) parameter at the end of the parameter list, there is no chance of affecting any existing code. You must control the transaction from database a. It is the only way if you want to call this remote procedure syncronously (you can run it asyncronously using dbms_job@the_remote_site)...

Rating

  (42 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Handling Errors in a distributed Transaction

Ivan, September 30, 2002 - 4:18 pm UTC

I can think of one case where DATABASE B needs to do a commit when it is being called from DATABASE A. The case being to log errors. How can you log errors in DATABASE B if DATABASE A has the only way to commit?

My scenerio is I have a remote loader who updates data in our main server. However a log file needs to be populated for all changes that happen to the database. However is an error occurs than the errors are never logged because it will never all DATABASE B to commit the logging.

Before we had distributed transactions I was able to use PRAGMA AUTONOMOUS_TRANSACTION and commit the error. Now I am unable in 8.1.7.2.1.

Your thoughts please...

Tom Kyte
October 01, 2002 - 9:35 am UTC

UTL_FILE would be an opportunity there.

If an error occurs, the changes NEVER occurred and hence, why would you want to commit log messages that never happened??

That the autonomous transaction *sometimes* and in very specific cases worked in 816 was a bug -- it was a dangerous situation.




Writing to a table within the database

ivan, October 10, 2002 - 1:58 pm UTC

Tom,

This is a follow up to my previous post in this subject.

I wasn't very clear on what I was writing to and the purpose. I am calling a package from another Oracle server and trying to commit into a table (distributed transaction). The purpose is to log errors into an error table so that I can see where the loader is not following the "rules". Whether it is a loader trying to update a column that they do not have rights to or when a column changes (history). I thought UTL_FILE just writes to a text file. I tried to use DBMS_PIPE but I still get a "ORA-00164: autonomous transaction disallowed within distributed transaction" error.

How can I do this?

Tom Kyte
October 11, 2002 - 7:39 pm UTC

Sorry, i thought I was clear -- you cannot, not in a distributed transaction.

UTL_FILE was my attempt to give you a workable solution, one that would let you capture the errors and move forward.

Autonomous transaction disallowed - why?

Ranga Chakravarthi, October 10, 2003 - 3:35 pm UTC

Tom,

"That the autonomous transaction *sometimes* and in very
specific cases worked in
816 was a bug -- it was a dangerous situation."
Could you please explain why it is dangerous?
Why can't I do an autonmous transaction over a distributed
transaction? Why is it disallowed?
TIA

Tom Kyte
October 10, 2003 - 4:32 pm UTC

in 8i, it was NOT supported.

in 9i it is now supported.

Reason for not allowing an autonmous transaction over distributed

Ranga Chakravarthi, October 13, 2003 - 3:22 pm UTC

Tom,

Could you comment on why it was not supported and what
the reason was for disallowing it?

Thanks

Tom Kyte
October 13, 2003 - 8:05 pm UTC

it wasn't supported -- thats all that can be said.

the code didn't exist.
therefore, it didn't work.

About -02041

Mariano, January 09, 2004 - 5:47 pm UTC

Hi, Tom.
I've read this page and its links (similar in fact to expert 1-on-1 chapter) but i cannot make sense about a situation i have with my databases.
i'm working in an 8.1.7.0.0, using it for a website with ASP and ODBC connection (The ora client in the web IIS server -not the same machine for the database server- is 9.2.0.4)
I'm using dbms_obfuscation_toolkit to encript/desencript passwords for the website but, cause this package is not working in my 8i, i send the password to be desencripted to a remote 9.2.0.4.0 database.
Since i changed the webserver oraclient from 7.3 to actual 9.2, when i try to execute the procedure i get ora-02041 error over and over again (this is not happening from sqlplus). in the remote database i just execute dbms_obfuscation_toolkit.des3decrypt and this action is wrapped in a procedure in my 8i with some data processing actions after using dbms_obfuscation_toolkit.

Can you suggest an action in order to correct this situation?
Regards

Tom Kyte
January 10, 2004 - 10:27 am UTC

ahh -- lets fixed the dbms_obfuscation thing.

It is a byte order issue. See

</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:791026226790#8473587738442 <code>

(doesn't affect the latest releases -- all platforms use the same byte ordering now)


You have an 8 byte key right now -- say the key was:

12345678

the key to unlock your data is:

43218765

swap the bytes -- in your decrypt just use the key:


substr(key,4,1)||substr(key,3,1)||substr(key,2,1)||substr(key,1,1)||
substr(key,8,1)||substr(key,7,1)||substr(key,6,1)||substr(key,5,1)


So, use the 8i stuff and just "fix the key" -- have your decrypt routine accept the key "as normal" but apply this tranformation to it.




Please don't answer my question

Mariano, January 09, 2004 - 7:32 pm UTC

now it's ok. it was all about dealing with MTS in the webserver.

regards.-

synonym for remote function doesn't work

James Su, February 05, 2004 - 5:33 pm UTC

SQL> create or replace function ff return number is begin return 200; end;
  2  /

Function created.

SQL> conn XXXX/XXXX@dev32
Connected.


SQL> create database link dbl_rep connect to XXXXXXX identified by XXXXXXXX using 'dev2';

Database link created.

SQL> select * from dual@dbl_rep;

D
-
X

SQL> select ff@dbl_rep from dual;

        FF
----------
       200

SQL> create or replace synonym sy_test for ff@dbl_rep;

Synonym created.

SQL> select sy_test from dual;
select sy_test from dual
       *
ERROR at line 1:
ORA-00904: "SY_TEST": invalid identifier

 

Tom Kyte
February 06, 2004 - 8:31 am UTC

look on the other page where you asked *the same thing*.

another question about remote function

James Su, February 06, 2004 - 9:15 am UTC

Sorry for posting my question twice. It seemed that something was wrong with this site yesterday. After I posted my question, I could never found it again.
I have a new question about remote function:

select sf_myfunction(colname)
from mytable@somelink
where ......
group by sf_myfunction(colname);

sf_myfunction is a local function and mytable is a remote table.
This query runs slowly. Can I improve the performance by moving sf_myfunction to @somelink that links to the same server where mytable located?

I was trying to do that yesterday and I failed to access to a synonym for remote function. Something is wrong with my Oracle9i for linux. So I am planning today to create a view on that server, and create a synonym for that view on the local server.

Tom Kyte
February 07, 2004 - 12:35 pm UTC

it takes a minute (or 15) for new things to be indexed. i update the text index on a schedule.


it probably would go faster to have a view at the remote site HOWEVER, I would recommend you look at my_function and say "do i really need a function or can i do this in sql" as that would be infinitely "faster" than calling plsql from sql.




sub sql vs function

James Su, February 09, 2004 - 10:08 am UTC

I can use a sub query instead of a function, but that will make the whole sql too complex. And the function is called more than once, in several sql statements. It's a hierarchical query using an argument as part of the "start with" clause, and I don't know how to implement it as a view other than a function. Another reason to use a function is that I can capture all the exceptions in the function and return a default value, and I don't know how to do that in a sub query. How much slower it could be to use a function instead of a subquery ?


Can you tell me which of the following is better? (suppose table B and table A has a one-to-many relationship and table A has a foreign key constraint on column b_id )

select A.*,B.colname
from table_a A,table_b B
where A.b_id = B.id;

select A.*,
(select B.colname
from table_b B
where B.id=A.b_id
)
from table_a A;

Thank you so much for your help.

Tom Kyte
February 09, 2004 - 10:28 am UTC

"views" - use a view to hide the "complex sql". it could well be the difference between

a) the query returning in a reasonable amount of time
b) the query never seeming to return at all


the two queries are not "the same"


select A.*,B.colname
from table_a A,table_b B
where A.b_id(+) = B.id;

and

select A.*,
(select B.colname
from table_b B
where B.id=A.b_id
)
from table_a A;


are if A.B_ID is nullable (if A.B_ID is not null -- then your two queries are the same).....


the first approach is the standard one.

a view based on hierarchical query

James Su, February 09, 2004 - 10:52 am UTC

hi Tom,
I thought of using a view to hide the complex sql. But, as I mentioned above,the function is a hierarchical query using an argument as part of the "start with" clause:

.......
SELECT CATL_TITLE
into v_sport
FROM CATEGORY,CATEGORTITLES
WHERE CTGR_PARENT=0 AND CTGR_ID = CATL_CTGR_ID
START WITH CTGR_ID=p_ctgr_id
CONNECT BY PRIOR CTGR_PARENT=CTGR_ID;

return v_sport;
.......

you see I use an argument "p_ctgr_id" in "start with".
How can I define a view to do that? Thank you.


Tom Kyte
February 09, 2004 - 10:58 am UTC

application contexts can be used for that - but if this query is going "into plsql code" (assuming that based on p_ctgr_id) what do you care if

a) the query is nastly complex
b) the query is simple

???

You can just use a parameterized cursor and "hide the nastiness" in a package spec somewhere (instead of a view)

create or replace package my_nasty_query
as
cursor c( p_ctgr_id in number ) is
select ..........;
end;




and then others would


for x in my_nasty_query.c( some_input )
loop
.....

hiding a complex sub sql

James Su, February 09, 2004 - 11:16 am UTC

I'm using this subquery in a view:

CREATE OR REPLACE VIEW VW_TRANSACTION AS
select TRANSACTION.*
,VW_ACCOUNT.*
,( SELECT CATL_TITLE
FROM CATEGORY,CATEGORTITLES
WHERE CTGR_PARENT=0 AND CTGR_ID = CATL_CTGR_ID
START WITH CTGR_ID=EVENTS.CTGR_ID
CONNECT BY PRIOR CTGR_PARENT=CTGR_ID
) as CTGRTITLE
from TRANSACTION
,VW_ACCOUNT
,EVENTS
,LINE
where TRANSACTION.ACC_ID = VW_ACCOUNT.ACC_ID
and TRANSACTION.LINE_ID = LINE.LINE_ID
and LINE.LINE_EVENT_ID = EVENTS.EVENT_ID ;

and I access to this view in my plsql:

select .......
from VW_TRANSACTION
where .......
group by CTGRTITLE;
^^^^^^^^^

I use this subquery in quite a few views, and I don't like to write it everytime. Is there any way to hide it?(other than a function)

Tom Kyte
February 09, 2004 - 12:07 pm UTC

no

Distributed transaction and Rollback segment

Sami, April 20, 2004 - 6:57 pm UTC

Dear Tom,

Thanks for your time and effort.

Version 8.1.7
The requirement is to update 2 databases using distributed transaction. Either both of them should be completed or none of them. We are updating the remote DB(in my case NewYork) using database link.


New York
=========
create or replace procedure p1
as
begin
set transaction use rollback segment BIG_RBS_NY;
for i in 1..10000
loop
update r1 set site=upper(site);
end loop;
end;
/

New Jersey
=========
create or replace procedure p1
as
begin
--set transaction use rollback segment BIG_RBS_NJ; <== middle of the
trasaction
for i in 1..10000
loop
update r1 set site=upper(site);
end loop;
end;
/


From New Jersey, I am invoking

New Jersey
=========
begin
p1@newyork;
p1;
end;
/

Assumption
1)update consumes lot of Rollback segment space on both sides
2)all or none. Both sites should be updated or none of them.

Question:

How do I specify the rollback segment for New Jersey database.
p1@newjersey did not go thru because of rollback segment error.

Any ideas how to get around this?

Thanks in advance

Tom Kyte
April 21, 2004 - 12:10 pm UTC

you need to contact the dba in newjersey and tell them they have misconfigured their database. (eg: you cannot).

I am a big believer in "set transaction use rollback segment" should be outlawed. I really like AUM in 9i for this reason -- there is no such statement anymore!! (we have an init.ora to "ignore" it)

Need your help

Sami, April 21, 2004 - 3:29 pm UTC

Dear Tom,

A)
newjersey dba is asking us to use rollback segment "BIG_RBS_NJ" but we cannot set that rollback segment because we are in the middle of the transaction.

our process is like below [both (1) and (2) are in single transaction]

--------transaction starts--------
(1)call procedure at NY from NJ over dblink
1a)set big_RBS
1b)huge DMLs
(2)call procedure at NJ from NJ
2b)huge DMLs
--------transaction ends--------

B) until we upgrade to 9i we have to work around with 8i limitation.

Tom Kyte
April 21, 2004 - 9:12 pm UTC

see above, my response does not change.


NJdba needs to set up equi-sized rbs's.

OK

Raju, April 21, 2004 - 11:32 pm UTC

Dear Sir,
After a procedure or function has been created successfully
Can we rename them? like
SQL> alter procedure p rename to proc;

But it throws errors.Do you have any other way to do this?
Please do reply. 

Tom Kyte
April 22, 2004 - 7:28 am UTC

No, you just drop the old and recreate the new.

Distributed database and optimizer modes, version 9.2.0.3.0

Raja, May 03, 2004 - 4:41 pm UTC

Hi Tom,
I don't know if this is the correct thread to ask this question. If not, please re-direct me to the more appropriate thread. Here's my question.....

We have a existing production database which uses RULE based optimizer. We are planning to move some tables and records within these tables to from the current database to another database(distributed/remote database) and will be doing a continuous archival of these records on a regular schedule based on certain date ranges.

However, we will be accessing the archived information quite often for dates which fall within the archived database range.

Now, the current database uses a RULE based optimizer (RBO), whereas, for the remote database, we are proposing that the COST base optimizer (CBO) be used.

I wanted to request your expert opinion on whether using RBO on one database and CBO on the other would evolve any potential issues/problems you could visualize and whether the 'Distributed Query Optimization' feature will be effectively used or would it even apply to this scenario at all.

Thanks in advance for your time and effort!


Tom Kyte
May 03, 2004 - 7:59 pm UTC

distributed query really relies on CBO and joining non-analyzed to analyzed tables is always a bad idea.

so, if you query both in a single query - that would be problematic.

ORA-164

A reader, May 26, 2004 - 10:53 am UTC

I have a simple update over the db link, and got 164 error.

How can I debug this?

Thanks.

SQL> update P2PA_FUDS_IN_STG_PRJ@p2_dev
  2  set project_name = 'K06TX003408 CON/HTRW TEST'
  3  where project_number = 102774;
update P2PA_FUDS_IN_STG_PRJ@p2_dev
*
ERROR at line 1:
ORA-00164: autonomous transaction disallowed within distributed transaction
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-04092: cannot COMMIT in a trigger
ORA-04088: error during execution of trigger 'APPS.P2PA_FUDS_IN_STG_PRJ_TRG'
ORA-02063: preceding 4 lines from P2_DEV
 

Tom Kyte
May 26, 2004 - 12:49 pm UTC


ORA-00164: autonomous transaction disallowed within distributed transaction



which indicates to me that that table has a trigger, trigger has an autonomous transaction in it and that is a hugely bad bad bad bad bad idea.


that trigger should not exist, I say that without even knowing what it does - I can make it misbehave and do things the coder did not ever anticipate.

Call remote procedure to initiate MV refresh

A reader, June 11, 2004 - 4:43 am UTC

Hi Tom

we have a process that populates various tables, which have Materialized View logs on them. Once we have finished our days processing, we want to refresh the Materialized views on a separate instance.
Can we call a procedure / package on the remote database, via a db link, to call the dbms_refresh.refresh procedure ?
Is this the best way to do this ?

Many thanks

Tom Kyte
June 11, 2004 - 3:49 pm UTC

there can be issues with calling a remote procedure that does a commit, so i would recommend that you call "dbms_job@remote_site" to schedule a refresh instead.


so, just:

create synonym remote_dbms_job for dbms_job@remote;

and call

remote_dbms_job.submit( l_job, 'dbms_mview.refresh( ... )', instance => remote_dbms_job.any_instance );





A reader, January 05, 2005 - 5:17 pm UTC

That the autonomous transaction *sometimes* and in very
specific cases worked in
816 was a bug -- it was a dangerous situation."
Could you please explain why it is dangerous?
Why can't I do an autonmous transaction over a distributed
transaction? Why is it disallowed?
TIA
----------------

How come a bug in prior release of Oracle 8i becomes a feature of 9i. that was discontinued in Oracle?

---
I have a very specific requirement where I have log table that need to be used to log the errors to a database whenever all the other changes are rolled back. I need to only commit the logs in a separate instance thru a db link

Could you please suggest a solution..

Thanks!



Tom Kyte
January 05, 2005 - 8:07 pm UTC

you will have to

a) rollback;
b) insert into table@remote;
c) commit;

is all. no need for an atrans here - you just said "when all else are rolled back" -- so you just need "a transaction"

A reader, January 06, 2005 - 10:32 am UTC

How will it work in case of triggers?

Tom Kyte
January 06, 2005 - 11:17 am UTC

what triggers?

A reader, January 06, 2005 - 12:01 pm UTC

I mean database triggers. Commit don't work in triggers. I will have to do it thru autonomous transaction. Is it changed. If so how can I accomplish it thru triggers. What I intend to do is to use the same procedure or a different one to capture errors from database triggers

Thanks for the help

Tom Kyte
January 06, 2005 - 12:41 pm UTC

umm, no - the caller should do this logging.  The person that runs this process should do that.


you don't want to remotely log via a trigger, mostly because "you cannot", but even still -- you don't want to.


say I have a table T.
In table T there are two rows -- only two rows.

Tell me, what is the maximum number of times a row trigger will fire on that table?


ops$tkyte@ORA9IR2> create table t ( x int, y int );
 
Table created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> insert into t values ( 1, null );
 
1 row created.
 
ops$tkyte@ORA9IR2> insert into t values ( 2, null );
 
1 row created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace trigger t_trigger
  2  before update on t for each row
  3  begin
  4          dbms_output.put_line
  5          ( 'for key = ' || :new.x ||
  6            ' we are changing y from "' ||
  7            :old.y || '" to "' || :new.y || '"' );
  8  end;
  9  /
 
Trigger created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> pause
 
ops$tkyte@ORA9IR2> update t set y = 42 where x > 0;
for key = 1 we are changing y from "" to "42"
for key = 2 we are changing y from "" to "42"
for key = 1 we are changing y from "" to "42"
for key = 2 we are changing y from "5" to "42"
 
2 rows updated.
 


Hmm, if I were to have done something non-transactional in that trigger, i could be in a big heap of trouble.  A-trans are generally "evil", if you are using them, we really need to explore "why", they have 100% fallen out of favor with me, I haven't really seen any appropriate uses of them.


(hint, during the pause, i ran:

ops$tkyte@ORA9IR2> update t set y = 5 where x = 2;
for key = 2 we are changing y from "" to "5"
 
1 row updated.
 
ops$tkyte@ORA9IR2> commit;
 
Commit complete.

in another session)


do NOT do things in triggers that are NOT transactional -- you'll get very well burnt over time if you do.

 

A reader, January 06, 2005 - 4:59 pm UTC

I am asking about, how I to do logging in a trigger, if there is an exception in the trigger itself.

For example
create or replace trigger my_trigger
after insert on my_table
for each row
...
BEGIN

rest of the processing...
..
exception when others
Log_error
..
end ;

How do I achieve it

Thanks!



Tom Kyte
January 06, 2005 - 7:23 pm UTC

read the above and ask "do I really want to" or do i want to

exception
when others then
raise_application_error( ...., ....... );
end;

to just FAIL the statement and let the caller, who is responsible after all for figuring out whether this transaction is just "dead" and must be rolled back or "survivable" and can continue, figure out what is best to do.


(i many times wish we didn't have triggers, or when others, or a-trans, or lots of stuff....)



A reader, January 07, 2005 - 10:14 am UTC

I am giving up. Your answers are really useless

Tom Kyte
January 07, 2005 - 10:19 am UTC

bravo, go for the triggers -- you've been told how to do this right, but hey -- there you go.


trigger should FAIL the statement

client or top level should LOG ERRORS resulting from failed statements.


doing things that are NON TRANSACTION in triggers is a provably *bad idea* -- that and what you are asking to do *just cannot happen*. Sorry I could not rewrite the Oracle Kernel to make you happy -- sometimes things work the way they work -- not the way "a reader" would like them to work.

This is like asking "how do I make a symbolic link on Windows" and getting mad when told "well, you don't really -- here is how to achieve the closest thing"

Hmmm

Tarry Singh, January 07, 2005 - 11:58 am UTC

'a reader', you just can't handle a bit of tech discoussion, now can you.

Nothing is useless, even your comments aren't useless. People will read them and NOT/WON'T follow them..heh

A reader, January 07, 2005 - 12:41 pm UTC

Given the situation. I would have gone for autonomous transaction with care, by commiting the logs that I need and rolling back the other. This is even a suggested method in metalink - I don't recall the document or thread and I have implemented it. I was bit curious when you said this is a bad idea..

Anyway thanks for the help



Tom Kyte
January 08, 2005 - 3:50 pm UTC

the a-trans is a ticking time bomb.

the a-trans in a trigger is pure evil (i hope you can sort of see why with the example above)

the trigger logging an error over a dblink is a bug itself, in the design. So what happens when the dblink fails, when the other site isn't up. Oh, gee, so sorry -- you cannot insert good data into this table, because the remote site is down right now -- no work for you.

There are so many reasons this is a bad idea (tm)

a) it quite simply is not a supported operation
b) dblinks in a trigger doing this make the entire system fragile
c) doing things that are not transactional in the trigger is a huge mistake

and so on.


The error logging quite simply doesn't belong here. People try to be really fancy and have 50 things happen by magical side effects from triggers and all they end up doing is shooting themselves in the foot.

So what happens when the "due care" you take to find some way to accidently make the atrans work -- stops working when patch X is applied, or when version B is installed, or some other piece of code is added that makes your a-trans just stop working in the current release?

one more clarification

raajesh, May 03, 2005 - 1:15 am UTC

how can i call a .sql file from a stored procedure..

Tom Kyte
May 03, 2005 - 8:48 am UTC

you cannot, sqlplus runs scripts -- plsql is not sqlplus. You'd need to write a program that read a file, parsed it, executed the sql therein.

You could write a plsql procedure do that that, but you should just use sqlplus at that point.

how do i call procedure from oracle database and execute it

Mamata, December 09, 2005 - 2:07 am UTC

i had created a procedure and stored it in database. but now when i run it it does not run..what do i do?

Tom Kyte
December 09, 2005 - 2:14 am UTC

one would typically demonstrate how one is attempting to run something in order to get an answer ;)

how about an EXAMPLE?

got error ORA-02041 when calling a packaged.

Sean, March 03, 2006 - 11:15 am UTC

I also got this error
ORA-02041: client database did not begin a transaction

I guess that it is related to calling procedure in another database, but I could not be able to repeat the error using simple code, which means that I don't know what cause this error.

Both database is 9207.

Thanks so much for your help.


DATABASE A and DATABASE B

Mark, March 09, 2006 - 8:50 am UTC

I'm a little fuzzy on this.

Database A is our live system.
Database B is our read-only reporting system.

We use Database B for reports that generally load the LIVE server down too much.

What I want to know is if I have an identical function on Database A and Database B:
FUNCTION GET_GROUPTOTALS(in_group_id in number)
returns number
is
v_return number;
begin
select sum(amount)
into v_return
from my_transactions
where group_id = in_group_id;

return v_return;
end;
/

I want to know which database the FUNCTION is getting it's totals from in these SQLs.

This one runs on DATABASE A entirely (no db link):

SELECT GET_GROUPTOTALS(g.group_id)
FROM my_groups g;

What about this one:
SELECT GET_GROUPTOTALS(g.group_id)
FROM my_groups@DATABASE_B g;

My guess is that the last statement runs the function on DATABASE A because internally it access's the local database (no db link), even though you are passing values from DATABASE_B via the db link.

Do I have this right in theory?

Tom Kyte
March 09, 2006 - 2:39 pm UTC

you would be running the local copy of the function, it would get the data from "g" and then run the local function.

dbms_job and db_link

Branka, March 15, 2006 - 6:49 pm UTC

I created job, that execute SP
In SP I query local and remote database.
I get error:

ORA-12012: error on auto execute of job 6
ORA-01017: invalid username/password; logon denied
ORA-02063: preceding line from CDSP
ORA-06512: at "CDS01.COMPARE_CDS_AND_CDSP", line 218
ORA-06512: at "CDS01.COMPARE_CDS_AND_CDSP", line 70
ORA-06512: at line 1

When I logon and execute same job, I don't have problem.
Any suggestion?
Thanks
Branka


Tom Kyte
March 16, 2006 - 7:48 am UTC

you have a database link created without a username and password.

It therefore uses the password of the currently connected session to open the dblink.

In the job, there is no password for the current session - therefore there is no password that can be used to open the dblink to the remote site.

dbms_job and db_link

Branka, March 16, 2006 - 9:48 am UTC

In other words, If I want to use dbms_job, and I have db_link I have to create db_link like:
CREATE DATABASE LINK TEST_DB_LINK CONNECT TO TEST_USER IDENTIFIED BY test_password USING 'TEST_DATABASE'

Is it any way I can solve this problem without creating db_link with username and password?
DB group in this company insist on private db_link without username and password.
Thanks


Tom Kyte
March 16, 2006 - 2:32 pm UTC

you can use other types of dblinks but they require directories and such (and the storing of credentials).



dbms_job and db_link

Branka, March 16, 2006 - 3:05 pm UTC

I didn't understand this.
Did you say that I can use db_link created like :
CREATE DATABASE LINK test_link USING 'test_db'
and still schedule dbms_job to execute SP that have db_link.



Tom Kyte
March 16, 2006 - 3:12 pm UTC

not without storing the credentials somewhere, you are by definition "not there to supply them"

db_link and dbms_job

Branka, March 16, 2006 - 3:53 pm UTC

Where can I store the credentials? I use Oracle9i.
In DBMS_JOB I can execute only SP. That mean that I should store credentials somewhere in sp?
Is it correct?

Tom Kyte
March 17, 2006 - 4:38 pm UTC

In the simpliest form, you would have a dbline with the username/password.

You can also use a directory (LDAP) to store the credentials or a wallet. but, you'd have to get your DBA to "help you"

I'm confused

Steven Zhang, March 17, 2006 - 12:01 am UTC

Hi Tom,
   You Said "In a distribute transaction -- one in which "DATABASE A" calls "DATABASE B", only "DATABASE A" may commit -- " 

But here is an example,I can start a transaction at Database A, and then commit at Database B via a procedure.
--------------------------------------------------------
SQL> create database link sprrsteven connect to a identified by a using 'EASTPRD1';
Database link created.
SQL> insert into t values(1);
1 row created.
SQL> insert into t@sprrsteven values(2);
1 row created.
SQL> exec p@sprrsteven
PL/SQL procedure successfully completed.

What the procedure in remote db 'EASTPRD1' is like :

QL> create procedure p as
  2  begin
  3  insert into t values(1);
  4  commit;
  5  end;
  6  /
Procedure created.
--------------------------------------------------
The procedure p is parsed and executed at remote site.And it issues a commit.So the distribute transaction is commited at remote site,not local site.

Is there any conficts with your explaination?

Thanks,
Steven  

Tom Kyte
March 17, 2006 - 5:17 pm UTC

it is not supported. It can and will fail under various scenarios - I would not suggest doing it.

It is one of the reasons DDL over a dblink isn't supported (and autonomous transactions and other transaction control statements in fact)

$ oerr ora 2074
02074, 00000, "cannot %s in a distributed transaction"
// *Cause: A commit or rollback was attempted from session other than
// the parent of a distributed transaction.
// *Action: Only commit or rollback from the parent session.


Two-Phase Commit/Distributed Transactions

Mark, April 13, 2006 - 2:50 pm UTC

Hey Tom,

I have a question on two-phase commit/distributed transactions. From the Wikipedia article on Two-Phase Commit - </code> http://en.wikipedia.org/wiki/Two_phase_commit <code>:
---
Disadvantages
The greatest disadvantage of the two phase commit protocol is the fact that it is a blocking protocol. A node will block while it is waiting for a message. This means that other processes competing for resource locks held by the blocked processes will have to wait for the locks to be released. A single node will continue to wait even if all other sites have failed. If the coordinator fails permanently, some cohorts will never resolve their transactions. This has the effect that resources are tied up forever. The algorithm can block indefinitely in two ways:

1. When the coordinator has sent commit to the cohorts, it will block until all cohorts have acknowledged. Thus, if a cohort is permanently down, the coordinator will block indefinitely.

2. When a cohort has sent an agreement message to the coordinator, it will block until a commit or rollback is received. If the coordinator is permanently down, the cohort will block indefinitely.

Another disadvantage is the protocol is conservative. It is biased to the abort case rather than the complete case. Also it cannot recover from cases where a node has failed in the commit stage (due to internal or network failures) after indicating that it is ready to commit. In this case, resources that committed prior to this failure cannot be rolled back.

A lot of database research has been done on ways to get most of the benefits of the two-phase-commit protocol without the costs.
---

(That last sentence is a bit vague, but I figure if anyone has found a way around the costs, Oracle has implemented it.)

Could you possibly comment on these disadvantages when using distributed transactions, and how to deal with them in Oracle (or how Oracle deals with them)? Does Oracle's multi-versioning play a role in limiting these blocks?

Thanks,
Mark

Tom Kyte
April 14, 2006 - 12:01 pm UTC

the resources will be locked - but because you have been MODIFYING them (they were in fact locked well before the commit started).

The obvious disadvantage of the 2pc is that - well - it is distributed, there is more than one player - more can go wrong. And yes, if something like the coordinator fails - the participants get sort of stuck (if they voted YES to commit and are awaiting the outcome of the vote). Here, Oracle has methods to manually force the distributed in doubt transactions.


And yes, we have some "faster than 2pc" ways to "2pc" in various environments - for example, our AQ code has optimizations when pushing queues from one machine to another. It is sort of a 2pc, but can take shortcuts since we know the number of participants and control the data entirely.

But in general, a 2pc for you will be a 2pc.

Thanks!!!

Mark, April 14, 2006 - 5:50 pm UTC


dbms_output does not send the text over the dblink

A reader, June 21, 2006 - 5:03 pm UTC

Tom,
Is this an expected behavior? Any work-around by which I can display the dbms_output over the dblink?

My database version is 9.2.0.7 Both databases are on Solaris 2.8.

In my local database:

CREATE OR REPLACE PROCEDURE call_me IS
BEGIN
  dbms_output.put_line ('
  Hello world!');
   EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       RAISE;
END call_me;

Procedure created.
sql>

In my remote database:

SQL> set serverout on
SQL> exec vigat.call_me@db_link
PL/SQL procedure successfully completed.
SQL> 

I do not see any output. 

Thanks for your help 

Tom Kyte
June 22, 2006 - 11:48 am UTC

that'll be writing to the dbmsoutput@db_link package. In order to "see it", you would have to

a) run dbms_output.enable@db_link (just to enable it at the remote site)
b) run your procedure (which populates the remote dbms_output package)
c) run dbms_output.getXXXX@db_link (two different apis to get the remote data) to retrieve the remote data and call dbms_output locally to "print it"



HINT:

when others then
raise;


is a

a) waste of keystrokes
b) a worst practice
c) a way to simply hide the line number that the error happened on
d) not useful
e) something to remove from your coding practices

Thanks

A reader, June 28, 2006 - 11:40 am UTC

Tom,

Thanks for the advice on not using RAISE.

Could you please explain what you mean by:

run dbms_output.getXXXX@db_link

What is XXXX here?

thanks.

Tom Kyte
June 28, 2006 - 4:41 pm UTC

ops$tkyte@ORA9IR2> desc dbms_output
PROCEDURE DISABLE
PROCEDURE ENABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 BUFFER_SIZE                    NUMBER(38)              IN     DEFAULT<b>
PROCEDURE GET_LINE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 LINE                           VARCHAR2                OUT
 STATUS                         NUMBER(38)              OUT
PROCEDURE GET_LINES
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 LINES                          TABLE OF VARCHAR2(255)  OUT
 NUMLINES                       NUMBER(38)              IN/OUT</b>
PROCEDURE NEW_LINE
PROCEDURE PUT
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 A                              VARCHAR2                IN
PROCEDURE PUT
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 A                              NUMBER                  IN
PROCEDURE PUT_LINE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 A                              VARCHAR2                IN
PROCEDURE PUT_LINE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 A                              NUMBER                  IN


the "get" routines to retrieve the dbms_output buffer contents from the remote site. 

Calling procedure over db_link

Santanu, February 26, 2008 - 3:56 pm UTC

Hi Tom,

I believe you surely have the answer of the following problem.

I need to call procedure proc2 in db2 from proc1 at db1 over database link. I am using local loopback for easy testing purpose. Using 10g database.

CREATE DATABASE LINK hq.acme.com@hq_1
connect hq_1 identified by pass_hq_1
USING 'string_to_hq_1';

I created synonym of proc2 with the db link in db1.

Proc2 procedure is working fine with input parameter as number and saving it in table.
But it is not working when input parameter is of either XML Type doc (dbms_xmlgen.getxmltype) or collection of object (table of database type).

Compilation errors for PACKAGE BODY
Error: PLS-00306: wrong number or types of arguments in call to 'proc2'.

Please let me know if oracle does not permit this operation or I am doing something wrong. In actual case it won¿t be loopback db link. It will be two different databases.

Best regards,
Santanu

Tom Kyte
February 26, 2008 - 4:06 pm UTC

the remote database doesn't know of your local types, you would need to use the remote types at best.

just because two types have the same "name" doesn't mean they are the same.

Calling procedure over db_link

Santanu, February 26, 2008 - 4:26 pm UTC

Not clear Sir. In the following case xmtype is general one.

proc1 in db1--> procedure proc1()
begin
v_xml :=dbms_xmlgen.getxmltype(ref cursor);
synonym_proc_2(v_xml);
end;

Proc2 in db2--> procedure proc2(p_xml xmltype) is
begin
dbms_xmlstore ...
end;

Is loopback db_link is creating problem?

Best Regards,
Santanu

Tom Kyte
February 27, 2008 - 2:23 am UTC

no, they are not the same

pretend it is not a loopback, because we do (pretend it is not)

there is the local type XMLType, there is the remote type XMLType and object types are not database link friendly.

Thank you

Santanu, February 27, 2008 - 8:29 am UTC

Thank you Tom.

Best regards,
Santanu

db link stored procedures out parameter

Raju, October 23, 2009 - 9:33 am UTC

Hi Tom,

this is a great thread on calling stored procedures through database links. But a question i have though is , when i am calling a stored procedure (with an out parameter) through database link, at the calling side, i always get a null value for the out parameter.

example :

database A:

declare
var1 number;
param1 number;
param2 number;
param3 number;
begin
proc1@link_B(param1,param2,param3,var1);
end;

where param1, param2,param3 are input parameters and var1 is an output parameter. i get null value for var1.
the database version is : 9.0.2
Please respond.
Tom Kyte
October 23, 2009 - 2:50 pm UTC

if what you say is true and you can verify that var1 should in fact have a value

that is, you can produce a cut and paste that looks just like this:

SQL> variable var1 number
SQL> connect user/pass@whatever_link_b_points_to
SQL> exec proc1( 1,2,3,:var1)
SQL> print :var1
SQL> connect user/pass@database_you_are_using_now
SQL> exec proc1@link_b( 1,2,3,:var1 );
SQL> print :var1

can you do that and cut and paste the results.

distributed transaction

A reader, March 31, 2013 - 3:39 pm UTC

Hi,Tom
I have a question about Oracle distributed transaction.
I have read almost all docs about distributed transaction on tahihi.oracle.com website,But I can find a statment about this:
Can Oracle always guarrantee the data consistent in a distributed transaction?
For example,there is a distributed transaction on node a,node b and nod c.
node b and node c informed node a they were prepared,
so node a committed,and inform node b and node c commit.
then node b committed and feedback,but network on node c broken at this point,So node a can't not get feedback from node c,but node a and node b has been committed, so what will Oracle do in this condition?
If node c rollback ,the data on local node, consistent in this distributed transaction was failed ,yes?

Could you please give some explanation and tell if this statement is true?
Can Oracle always guarrantee the data consistent in a distributed transaction?

Thank you very much!
alan
Tom Kyte
April 22, 2013 - 12:50 pm UTC

you have a distributed in doubt transaction at node C, it will either resolve it naturally by itself when the coordinator becomes available again or a DBA can force it (they could for example call the DBA at site A and ask them for the outcome)

http://docs.oracle.com/cd/E29505_01/server.1111/e25789/transact.htm#sthref1381

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library