Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Anne.

Asked: July 05, 2000 - 8:22 am UTC

Last updated: July 16, 2013 - 4:28 pm UTC

Version: 8.0.5

Viewed 10K+ times! This question is

You Asked

Hi,

The situation is whenever a "delete" statement
is issued there should be a log that should store the info
in another table. We are trying to do this
while using a statement trigger..
But, we don't want log this this info if the delete is issued from another trigger.
Is there any way to know who fired the trigger, direct order or order from another trigger ?

Thanks in advance,
Anne Cantrelle


and Tom said...

If you get the who_called_me routine from
</code> http://asktom.oracle.com/~tkyte/who_called_me/index.html <code>
we can determine this. Consider this example in 8.0.6:

scott@ORA806.WORLD> create table t1 ( x int );

Table created.

scott@ORA806.WORLD> create table t2 ( x int );

Table created.

scott@ORA806.WORLD>
scott@ORA806.WORLD> create or replace trigger t1_trigger
2 before insert on t1
3 for each row
4 declare
5 owner varchar2(30);
6 name varchar2(30);
7 lineno number;
8 caller_t varchar2(30);
9 begin
10 who_called_me( owner, name, lineno, caller_t );
11 dbms_output.put_line( '--------- in T1 trigger ---');
12 dbms_output.put_line( 'My Caller is ' ||
13 owner || '.' || name );
14 dbms_output.put_line( 'It is a ' || caller_t );
15 dbms_output.put_line( '--------- end T1 trigger --');
16 end;
17 /

Trigger created.

scott@ORA806.WORLD>
scott@ORA806.WORLD> create or replace trigger t2_trigger
2 before insert on t2
3 for each row
4 declare
5 owner varchar2(30);
6 name varchar2(30);
7 lineno number;
8 caller_t varchar2(30);
9 begin
10 who_called_me( owner, name, lineno, caller_t );
11 dbms_output.put_line( '--------- in T2 trigger ---');
12 dbms_output.put_line( 'My Caller is ' ||
13 owner || '.' || name );
14 dbms_output.put_line( 'It is a ' || caller_t );
15
16 insert into t1 values ( :new.x );
17
18 dbms_output.put_line( '--------- end T2 trigger --');
19 end;
20 /

Trigger created.


So, the triggers should attempt to print out what is causing them to fire -- the trigger on T2 inserts into T1 so we expect to be able to discover that. We'll run inserts into t1 and t2 from the command line and procedures to see what happens:

scott@ORA806.WORLD>
scott@ORA806.WORLD> create or replace procedure p1
2 as
3 begin
4 insert into t1 values(1);
5 end;
6 /

Procedure created.

scott@ORA806.WORLD> create or replace procedure p2
2 as
3 begin
4 insert into t2 values(2);
5 end;
6 /

Procedure created.

scott@ORA806.WORLD>
scott@ORA806.WORLD> set serveroutput on
scott@ORA806.WORLD>
scott@ORA806.WORLD> insert into t1 values (1);
--------- in T1 trigger ---
My Caller is .
It is a
--------- end T1 trigger --

1 row created.

The straight insert shows "NULL" is our caller type. We were called from the command line...

scott@ORA806.WORLD> insert into t2 values (2);
--------- in T2 trigger ---
My Caller is .
It is a
--------- in T1 trigger ---
My Caller is SCOTT.T2_TRIGGER
It is a TRIGGER
--------- end T1 trigger --
--------- end T2 trigger --

1 row created.

In this one, the insert into T2 shows NULL but the insert into T1 shows that it was initiated by a TRIGGER -- T2_TRIGGER specifically

scott@ORA806.WORLD>
scott@ORA806.WORLD> exec p1
--------- in T1 trigger ---
My Caller is SCOTT.P1
It is a PROCEDURE
--------- end T1 trigger --

PL/SQL procedure successfully completed.

When run by a procedure -- we can tell...

scott@ORA806.WORLD> exec p2
--------- in T2 trigger ---
My Caller is SCOTT.P2
It is a PROCEDURE
--------- in T1 trigger ---
My Caller is SCOTT.T2_TRIGGER
It is a TRIGGER
--------- end T1 trigger --
--------- end T2 trigger --

PL/SQL procedure successfully completed.

And again, T2 can tell it was inserted into by a trigger and T1 can tell it was inserted into by the trigger T2_TRIGGER....



Rating

  (32 ratings)

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

Comments

exactly what i need...

A reader, March 24, 2003 - 4:26 am UTC


Related question: Who (user) fired the trigger

Anil, June 23, 2003 - 4:35 pm UTC

I use a table trigger to limit DML actions on one (or more) columns of the table by a user who is not the owner of the table. (I cannot use views). To add to the complexity, the trigger is defined in a separate schema with create any trigger privilege and this user does not have any other special privileges. Simply put, I am maintaining column level privileges to user tables with a PL/SQL APIs to grant and revoke privileges on some special columns. The triggers are maintained in a special schema along with the dictionary (privilege) information.

In the current implementation, I am using SYS_CONTEXT('USER_ENV','CURRENT_USER') to check if the user modifying the content in the column has the privilege to do so. This works fine as long as the end user is performing direct INSERT/UPDATE into this table. But this approach fails if the owner of the table creates a procedure to perform the DML and grants execute privileges on this procedure to other users. In this case, no matter who invokes the procedure, the insert into the column should go through as the owner (of the procedure and the table) always has the full access to the column. But, the use of
SYS_CONTEXT('USER_ENV','CURRENT_USER') is restricting this operation because it always computes to the original caller of the procedure and not the owner of the procedure (or the invoker of the DML statement).

So, to mimic the typical privilege model in the presence of user defined function/procedures, I would like to get the user who "issued" the INSERT/UPDATE statement (dynamic/static) within the trigger body. Is the who_am_i (like) procedure my only option ? Is there any trigger variable (like UPDATING) that can give this information ?

Your help is greatly appreciated.

Thanks,
-Anil.





Tom Kyte
June 24, 2003 - 7:27 am UTC

wow, and all of this could have be done with GRANT, too bad you did all of that work.

who am i will get you the owner of the invoking procedure. But you know, just erasing your code and using GRANT would be an option as well!

Thanks

Anil, June 24, 2003 - 10:45 am UTC


Yes, I could have used grant privileges on the columns. But when the user does grant insert on the table, I still want to restrict privileges on some columns (based on the datatype). The content of these columns is special and this is required to ensure that the other users do not get privileges on them when the owner simply does table level grant. I want the owner to take some explicit action so that he knows what he is doing.

Thanks for the response.
-Anil


MY_CALLER Function

Fred, August 01, 2003 - 10:29 pm UTC

Tom,

I have your sample MY_CALLER function from your book. Does this work on Oracle 9i?

Tom Kyte
August 02, 2003 - 7:49 am UTC

yes, it just parses the dbms_utility.format_call_stack output which exists in 9i

who_called_me

Ashwin N., October 16, 2003 - 9:06 am UTC

Hi Tom

I was trying to use the who_called_me procedure.
For some reason it falls up with the following error

ORA-06502: PL/SQL: numeric or value error: character to number conversion error-6502
(I have pasted my code below which calls this.)
I have traced the error and it comes up on the following line in who_called_me

lineno := to_number(substr( line, 13, 6 ));
I put debug messages just before this line and I get
the following values for
lineno=c0000000197b5a30 11 anonymous block
lineno= <BLANK>


I am sure I am doing something wrong here.
Can you please help on this

Thanks
Ashwin N.



PACKAGE BODY measure_time
AS
PROCEDURE set_time IS
BEGIN
time_before := DBMS_UTILITY.GET_TIME();
END;
PROCEDURE get_time(process_name IN VARCHAR2) IS
time_after NUMBER;
time_elapsed NUMBER;
prog_name VARCHAR2(30) ;
prog_owner VARCHAR2(30);
lineno VARCHAR2(30);
caller_t VARCHAR2(30);
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
DBMS_OUTPUT.PUT_LINE(1);
who_called_me(prog_owner,prog_name, lineno, caller_t);
DBMS_OUTPUT.PUT_LINE(2);
time_after := DBMS_UTILITY.GET_TIME();
DBMS_OUTPUT.PUT_LINE(3);
time_elapsed := (time_after-time_before)/100;
DBMS_OUTPUT.PUT_LINE(4);
INSERT INTO measure_time_table VALUES(prog_name,process_name,time_elapsed,SYSDATE);
COMMIT;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM||SQLCODE);
END;
END;



Tom Kyte
October 16, 2003 - 10:46 am UTC

the address is different then I anticipated -- just adjust the code a bit to parse it correctly on your server.

who_called_me

Ashwin N, October 16, 2003 - 9:09 am UTC

Just a small change

It Should have been

line=c0000000197b5a30 11 anonymous block
lineno= <BLANK>

Regards
Ashwin N

Pls clarify

A reader, December 29, 2003 - 5:52 pm UTC

In the last follup you said
Followup:
the address is different then I anticipated -- just adjust the code a bit to
parse it correctly on your server.

I am also getting the same pl/sql numeric value error.
Can u pls elaborate how to adjust the parse statement ?What
should be the substr.
lineno := to_number(substr( line, 13, 6 )); is giving the error.
To correct the problem i used substr(line,11,9).
Did i do the correct thing. How do I the "handle"address wont increase.

Do i need to adjust some more place

handle number name
0x51125dd8 6 procedure SCOTT.WHO_CALLED_ME
0x527b1d1c 12 SCOTT.TRG_AIU_TEST


Tom Kyte
December 29, 2003 - 6:49 pm UTC

put some dbms_output's in there and see what is being parsed and adjust the substr's appropriately!

dbmsoutput the "line" before substring:

dbms_output.put_line( '"' || line || '"' );

and use that output to see where to substr


Remote DB not working

A reader, December 29, 2003 - 7:04 pm UTC

I tried using your same example but did the insert on table t2 from a remote DB procedure p2_remote and it is not giving me the remote procedure name nor the owner/schema name.
but it works if i am in the same DB but different schema
Any clues to this one ?

Tom Kyte
December 29, 2003 - 7:50 pm UTC

just use dbms_utility to print out the call stack and see what you see -- i've never used the format call stack over a dblink and would not be at all surprised if the remote site didn't see the other "remote" site.

U r correct

A reader, December 29, 2003 - 10:00 pm UTC

The remote DB doesnot see that.I printed the stack to confirm.I think its tied to its own DB and stack info cannot cross from one DB to another remote DB

So what is the solution here to know who called the trigger in case of RPCs.
Thanx much

Tom Kyte
December 30, 2003 - 9:45 am UTC

there isn't an out of the box one.

Still any pointers to the soln if any ?

A reader, December 30, 2003 - 4:24 pm UTC

This looks like a tough one.
Thanx

Tom Kyte
December 30, 2003 - 4:58 pm UTC

not that i'm aware of, no.

How about dbms_pipe and remote DB

A reader, January 01, 2004 - 11:57 am UTC

Can we use dbms_pipe ,abms_alert , AQ on a Distributed DB for the above issue.

Can we sen a message to a pipe to be retrieved by a remote DB.
Still struggling with this issue of knowing who fired if the firing is done from a Remote DB.
Thanx

Tom Kyte
January 01, 2004 - 12:48 pm UTC

well, the caller can certainly PASS this information along -- but you'd have to trust the call "not to lie to you".

I don't see how pipes, alerts would give you anything.

AQ could, since the dequeuer could be a "known, trusted account" and you would just look at "user" to see if it is to be allowed to proceed

To fix the numeric error in who_called_me...

Mark, January 02, 2004 - 5:04 pm UTC

I made the following changes to correct the problem:

Line 30
FROM lineno := to_number(substr( line, 13, 6 ));
TO lineno := to_number(substr( line, 21, 6 ));

Line 31
FROM line := substr( line, 21 );
TO line := substr( line, 29 );

I'm on Oracle8i Enterprise Edition Release 8.1.7.3.0 - 64bit Production

Who fired the trigger

Anders MÃ¥rtensson, January 20, 2005 - 6:47 pm UTC

Excellent!
I've been looking for this for I don't know how long.
Thanks!

Does not work with Oracle Forms

Todor Botev, June 07, 2005 - 9:17 am UTC

Does not work with Oracle Forms and db links - at least on Oracle 8i:

</code> http://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=197738.1 <code>

Ravi, July 06, 2005 - 8:24 am UTC

Is there a way of telling a particular PL/SQL stored program unit is being called by an Oracle GUI tool for sure.
Last metalink post suggests Forms uses RPC, is that a hint for the above problem?
Tried testing that a Null value for format_call_stack as an indicator, but this value is incorrect as it is nulls between PL/SQL calls across databases.
Any suggestions?

Tom Kyte
July 06, 2005 - 8:31 am UTC

an oracle gui tool is just a client. a client is just a client. the client looks the same as sqlplus, toad, asp's whatever.



Link not working

Bart, July 06, 2005 - 12:05 pm UTC

Tom,

The link at the top (who_called_me) seems to be invalid.

</code> http://asktom.oracle.com/~tkyte/who_called_me/index.html <code>


Very useful bit of code if I remember well.




Bart

Menon, July 06, 2005 - 12:11 pm UTC

Package.Procedure name?

Shiju, July 08, 2005 - 4:49 am UTC

Tom,

dbms_utility.format_call_stack and who_am_i is excellent!

If we are in a function/procedure inside a package, is there a way to know the function/procedure also? Using dbms_utility.format_call_stack I could only get the package name as shown below.


create or replace procedure p(lcString in Clob, lnLength in number default 255)
as
temp Clob;
lnLength1 number;
begin
if lnLength > 255 then
   lnLength1 := 255;
else
   lnLength1 := nvl(lnLength,255);
end if;
temp := lcString;
WHILE( LENGTH( temp  ) > 0 )
LOOP
   dbms_output.put_line(substr(temp,1, lnLength1));
  temp  := SUBSTR( temp , lnLength1+1  );
END LOOP;
end;
/
create or replace package test_pkg
as
procedure test_pro;
end;
/

create or replace package body test_pkg
as
procedure test_pro
as
begin
p(dbms_utility.format_call_stack);
p('who_am_i:'||who_am_i);
end;
end;
/

SQL> exec test_pkg.test_pro;
----- PL/SQL Call Stack -----
  object      line  object
  handle    number  name
7D7814F0         6  package body INTERSPC.TEST_PKG
7D645A24         1  anonymous block

who_am_i:INTERSPC.TEST_PKG
PL/SQL procedure successfully completed.

Is there a way to get TEST_PKG.test_pro ? . If it is there, then that would be very much useful in error logging functionality.

Thanks,
Shiju 

Tom Kyte
July 08, 2005 - 7:51 am UTC

you can only know the package name, line number.

remember there can be dozens of functions with the same name. The OBJECT in this case is simply the package.

Universal fix the numeric error in who_called_me...

Jack, December 21, 2005 - 8:59 am UTC

Tom,
I had been using the who_called me procedure without a problem, then started getting the numeric error that others had mentioned. Obviously there had been a system change which caused the object handle string size to change. Here is a fix that will handle this possibility:

Replace lines 30-31:
lineno := to_number( substr( line,instr(line,' ',-1,2)+2,
instr(line,' ',-1,1)-instr(line,' ',-1,2) ));
line := substr( line, instr(line,' ',-1,1)+2 );


Tom Kyte
December 21, 2005 - 7:26 pm UTC

thanks, I've bookmarked this and hopefully will "fix it" in the download soon..

When was trigger last fired ?

Shalini, February 15, 2006 - 12:44 am UTC

Tom,

Is there any view/table for me to know when the trigger was last fired - if at all it fired ?

We have a trigger like following in our database -
create table t_LOGGER ( msg varchar2(4000) );
create public synonym t_LOGGER for t_LOGGER ;
grant INSERT,SELECT on t_LOGGER to PUBLIC ;


create or replace trigger
t_FAILED_TO_EXTENT_TEMP
after servererror on database
declare
begin
if ( is_servererror(1652) )
then
insert into t_LOGGER values ( 'ora_sysevent = ' || ora_sysevent );
insert into t_LOGGER values ( 'ora_login_user = ' || ora_login_user );
insert into t_LOGGER values ( 'ora_server_error = ' || ora_server_error(1) );
insert into t_LOGGER
select 'Sorts:'||SORTS||
'! DISK_READS:'||DISK_READS||
'! BUFFER_GETS:'||BUFFER_GETS||
'! LOADS:'||LOADS||
'! INVALIDATIONS:'||INVALIDATIONS||
'! PARSE_CALLS:'||PARSE_CALLS||
'! SQL_Text:'||SQL_TEXT
from v$sql
where (HASH_VALUE,ADDRESS) in
(SELECT HASH_VALUE,ADDRESS from v$open_cursor where sid
= (select sid from v$mystat where rownum=1) );
end if ;
end ;

In this trigger am capturing the SQL when Temp tablespace error comes.
We have been notified by our application team that last night they had problem with temp tablespace cant extend, and verified with the logs from application team.

However the above trigger was expected to fill in rows of a table regarding the SQL,but it didnt.

I have checked this complete scenario in a seperate DB and all worked fine there giving me proper SQLs.
But in this database, I didnt get any rows populated.
Any idea why ?

With Regards,
Shalini.

Tom Kyte
February 15, 2006 - 9:05 am UTC

no, we do not track that...


I wonder, does your alert show two ora-1652's right next to eachother?

Because, if... just if.... the insert as select was tempted to SORT... and it failed - then the entire transaction for the trigger would rollback.

if you use this:

declare
pragma autonomous_transaction;

begin
if ( is_servererror(1652) )
then
insert into t_LOGGER values ( 'ora_sysevent = ' || ora_sysevent );
insert into t_LOGGER values ( 'ora_login_user = ' || ora_login_user );
insert into t_LOGGER values ( 'ora_server_error = ' || ora_server_error(1) );
COMMIT;

insert into t_LOGGER
select 'Sorts:'||SORTS||
'! DISK_READS:'||DISK_READS||
'! BUFFER_GETS:'||BUFFER_GETS||
'! LOADS:'||LOADS||
'! INVALIDATIONS:'||INVALIDATIONS||
'! PARSE_CALLS:'||PARSE_CALLS||
'! SQL_Text:'||SQL_TEXT
from v$sql
where (HASH_VALUE,ADDRESS) in
(SELECT HASH_VALUE,ADDRESS from v$open_cursor where sid
= (select sid from v$mystat where rownum=1) );
COMMIT;

end if ;
end ;
/

(or you might use utl_file to open a file, write to it, then do the sql...)

Trigger performance

A reader, February 25, 2006 - 7:06 am UTC

Hi Tom,

Wanted to know the trigger performance on a heavily updatable table.

I have a fairly big table (2 million) & I'm going to write a trigger (after update) on it.
the trigger looks like this

---------------------------------------
CREATE OR REPLACE TRIGGER trigger1
AFTER UPDATE ON tab1
FOR EACH ROW
DECLARE


IF (:NEW.prov_status_id = 73 AND :NEW.action_type_id =2 )THEN

<Do the needful>

end if;

end;

----------------------------------------
the table is heavily updatable as well.
but my IF condidion (status_id = 73) is going to occur hardly e.g. 20 times a day.

so will it hamper the performace of the trigger??

thanks in advance.

Tom Kyte
February 25, 2006 - 11:21 am UTC

you can use a when clause which will only fire the trigger body WHEN the condition is met. see the create trigger command.


I myself don't like triggers, would rather see this in the transactional API that everyone calls (no one calls update - they call an API that does the right thing..). That is my personal preference.

COMMIT in procedure called trigger

A reader, February 27, 2006 - 2:27 am UTC

Tom,

I'm trying to call a procedure from a trigger.
And the procedure is doing some commit/rollback/savepoint.

so the trigger is throwing the error back as ORA 4092.

So can I not do any commit/savepoint in the procedure that is being called by the trigger??

Tom Kyte
February 27, 2006 - 7:09 am UTC

think about it - think about it long. and. hard.

You are in the middle of something there. You are in the MIDDLE of a transaction. Maybe you are updating 2 rows in a single update. Your trigger fires during the first one.

Do you *REALLY* want to call this procedure AND COMMIT?

If you say yes, then add "knowing that the second row is going to fail with a constraint error- rolling back - but wait, we committed, cannot roll back but we must rollback but we can't roll back

conundrum. confusion. bad bad bad idea.

Can you call this procedure? Absolutely. We could do that. It would just be about the wrongest thing you could possibly ever do in your life (so I won't really mention "how", just that "no, you shouldn't, period"



Who fired the trigger

Yogesh Purabiya, March 11, 2006 - 11:38 am UTC

I faced a strange problem few times
while populating some tables in a new database
created from the legacy database.
I may not be able to repeat / recreate that,
but would just describe the situation
as per my perception.

current login / Session user-name is PRMS

insert /*+ APPEND */ into PRMS.table1
select t1.*, 'VRO' from VRO.table1
where NOT exists
(select null from PRMS.table1 where RO_Abb = 'VRO');

It gave me error saying *something like*
the invalid trigger MRO.table_xxxx.trigger_xxxx
could not be re-validated.

After dropping
the trigger trigger_xxxx
on table_xxxx
of user MRO,
I could execute the statement successfully.

I wonder how come a trigger on a table
of some third user got fired ?!

I have created / defined an FGAC-policy
on table PRMS.table1
to restrict the row-selection by "RO_ABB = User".

There was (and is) no trigger on PRMS.table1.
There was (and is) no trigger on VRO.table1.

Well, the client was toad;
but, this time I could not doubt the client.

I feel there might be something
that I am missing.

Tom Kyte
March 11, 2006 - 3:51 pm UTC

... It gave me error saying *something like*
the invalid trigger MRO.table_xxxx.trigger_xxxx
could not be re-validated. ....


thousands of reasons, all caused by "you" basically. The trigger referenced a table you dropped elsewhere - therefore it went invalid and could not recompile. Or it referenced a package - that no longer exists. Or a revoke had been issued and a table it needs no longer is referencable.

You must have a trigger on prms.table1 that touched table_xxxx and fired the trigger - look to your OWN trigger logic to figure this out.

And by the way - simply dropping a trigger cause it got in the way - well, that is not exactly the approach I (or many others who care about their data, their data integrity) might have taken..

By the way part 2 - triggers make /*+ append */ a big "no-op", it doesn't append when triggers are there.

Who fired the trigger

Yogesh Purabiya, March 12, 2006 - 1:55 am UTC

This happened nearly 20 times
while populating various tables
in schema PRMS
selecting from 150 tables
from 12 different schemas / users.

This did not happen for PRMS.table1
for some users before it occured for user VRO.
i.e.,

insert /*+ APPEND */ into PRMS.table1
select t1.*, 'VRO' from VRO.table1
where NOT exists
(select null from PRMS.table1 where RO_Abb = 'VRO');

gave error, but

insert /*+ APPEND */ into PRMS.table1
select t1.*, 'DRO' from DRO.table1
where NOT exists
(select null from PRMS.table1 where RO_Abb = 'DRO');

did not give any error though it (DRO) was executed
prior to VRO.

I had dropped all the triggers
of all the tables
of the schema PRMS.

select * from User_Triggers;

gave me "No rows returned".

After that only I started population further.

I dropped so many (ALL the) triggers
because I did not want them to be fired at any cost
since this was loading of
legacy (static - read-only) data.
It was a precess of creating / building
of a new instance
used solely by me.
If need be there,
I can re-create (re-import) the triggers later on.

This is new to me : "By the way part 2 - triggers make /*+ append */ a big "no-op", it doesn't append when triggers are there. "


Tom Kyte
March 12, 2006 - 2:00 pm UTC

sorry - you have triggers, they are your triggers - they are not our triggers, your triggers have an error.


The data you have caused the triggers to change what they did.

perhaps (you - YOU - need to review YOUR logic to see what YOUR triggers do) when you execute:

insert /*+ APPEND */ into PRMS.table1
select t1.*, 'VRO' from VRO.table1
where NOT exists
(select null from PRMS.table1 where RO_Abb = 'VRO');

your trigger looks at that last column and says something like

if :new.column = 'VRO'
then
lets go and insert something over here ok....



and maybe that is what causes your error from your trigger.


again - dropping all triggers seems sort of silly, if you don't know what they do.



I am not able to use it

Payal, August 10, 2006 - 8:50 am UTC

All the details in the discussions were very useful but for some reason when i try to compile my trigger (using proc who_called_me) it says identifier who_called_me needs to be declared. I am using oracle 8i ....... why is this proc not available to me???

Tom Kyte
August 10, 2006 - 9:36 am UTC

because you did not create it I presume.

I wrote it, you need to get it and load it.

EXP / IMP & Trigger-Table_Owner

Yogesh Purabiya, December 23, 2006 - 2:36 am UTC

On this page I asked a query on March 11/12 2006.
I did not have any copy-paste and therefore I could not give much details.
Recently similar problem on a different server (hardware) and therefore different instance (SID).
After I imported a table form Live User (LU) to a dummy user (DU) (same instance)
The column Table_Owner of the User_Triggers view of the DU now shows as "LU";
hence the LU table insert fails, since the DU table trigger is INVALID.

The details (copy/paste) are as under.

(1)
exp sys/mymm06dbsys full=Y file=g:\oraexp\ears_full.dmp log=g:\oraexp\ears_full.log

Connected to: Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production
With the Partitioning option
JServer Release 8.1.7.0.0 - Production
Export done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR character set

About to export the entire database ...
<Deleted Several Lines Here>
. about to export DBSNMP's tables via Conventional Path ...
. about to export IPCLTOS's tables via Conventional Path ...

<Delete some lines here>

. . exporting table PUNCHDATASAP 2023922 rows exported

<Delete some lines here>

. . exporting table SAP_PUNCHDATA 6163542 rows exported
. . exporting table SAP_PUNCHDATA_23FEB2006 3486333 rows exported
. . exporting table SAP_PUNCHRECORD 1688605 rows exported

<Deleted several lines here>

. exporting statistics
Export terminated successfully without warnings.

(2)
imp system Full=n FromUser=ipclTos ToUser=Portal Tables=(PUNCHDATASAP,SAP_PUNCHDATA) ignore=n file=ears_full.dmp log=temp_20061220_2.log

Connected to: Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production
With the Partitioning option
JServer Release 8.1.7.0.0 - Production

Export file created by EXPORT:V08.01.07 via conventional path

Warning: the objects were exported by SYS, not by you

import done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR character set
. importing IPCLTOS's objects into PORTAL
. . importing table "PUNCHDATASAP" 2023922 rows imported
. . importing table "SAP_PUNCHDATA" 6163542 rows imported
IMP-00041: Warning: object created with compilation warnings
"CREATE TRIGGER "PORTAL"."DB_TR_PUNCHDATASAP" BEFORE INSERT ON "IPCLTOS"."PU"
"NCHDATASAP" FOR EACH ROW "
"DECLARE"
" CNT NUMBER(10):=0;"
"BEGIN"
" SELECT PUNCH_SAP.NEXTVAL INTO CNT FROM DUAL;"
" :NEW.SRNO := CNT ;"
"END;"
About to enable constraints...
Import terminated successfully with warnings.

(3)
12:33:27 portal@ >SELECT Trigger_Name, Trigger_Type, Triggering_Event, Table_Owner, Table_Name, Description
12:33:36 2 FROM User_Triggers
12:33:36 3 WHERE Table_Name = UPPER ('PunchDataSap')
12:33:36 4 /

TRIGGER_NAME TRIGGER_TYPE
------------------------------ ----------------
TRIGGERING_EVENT
--------------------------------------------------------------------------------
TABLE_OWNER TABLE_NAME
------------------------------ --------------------
DESCRIPTION
--------------------------------------------------------------------------------
DB_TR_PUNCHDATASAP BEFORE EACH ROW
INSERT
IPCLTOS PUNCHDATASAP
"PORTAL"."DB_TR_PUNCHDATASAP" BEFORE INSERT ON "IPCLTOS"."PUNCHDATASAP" FOR EACH
ROW


real: 63
12:33:37 portal@ >spo off

EXP / IMP & Trigger-Table_Owner

Yogesh Purabiya, December 23, 2006 - 3:49 am UTC

This is in continuation to the previous query from me.
Since I used the same singe SQL*Plus Session (i.e., same window)
for different Oracle Sessions / connections,
I spooled them on separate files and then merged / edited.
Here, Live User (LU) is actually IPCLTOS
and the Dummy User (DU) is PORTAL.

(4)

12:17:16 ipcltos@ >INSERT INTO ipcltos.PunchDataSap
12:19:14 2 SELECT -1, PUNCHDATE, PUNCHTIME, INOUT, MACHINEID, LOCCODE, PUNCHST, CMPLXCD, SAPUPFLG, ERRMSG, SRNO
12:19:14 3 FROM PunchDataSap WHERE 1=1 AND EmpCode = 16207625
12:19:14 4 AND ROWNUM < 11
12:19:14 5 /

10 rows created.

real: 16
12:19:16 ipcltos@ >roll
Rollback complete.
12:19:17 ipcltos@ >spo off

(5)

12:19:31 portal@ >Input truncated to 14 characters
set termout on
12:19:31 portal@ >alter trigger DB_TR_PUNCHDATASAP enable;

Trigger altered.

real: 31
12:19:56 portal@ >spo off

(6)

12:20:48 portal@ >set heading on echo off verify off termout on

USER UID TERMINAL ENTRYID
------------------------------ ---------- ---------------- ----------
SESSIONID DATE_AND_TIME
------------- -----------------
IPCLTOS 19 PC6093 0
27,21,015 23/12/06 12:21:23


real: 0



real: 16
12:20:48 ipcltos@ >Input truncated to 14 characters
set termout on
12:20:48 ipcltos@ >INSERT INTO ipcltos.PunchDataSap
12:21:02 2 SELECT -1, PUNCHDATE, PUNCHTIME, INOUT, MACHINEID, LOCCODE, PUNCHST, CMPLXCD, SAPUPFLG, ERRMSG, SRNO
12:21:02 3 FROM PunchDataSap WHERE 1=1 AND EmpCode = 16207625
12:21:02 4 AND ROWNUM < 11
12:21:02 5 /
INSERT INTO ipcltos.PunchDataSap
*
ERROR at line 1:
ORA-04098: trigger 'PORTAL.DB_TR_PUNCHDATASAP' is invalid and failed
re-validation


real: 32
12:21:03 ipcltos@ >roll
Rollback complete.
12:21:08 ipcltos@ >spo off

(7)

12:21:31 portal@ >Input truncated to 14 characters
set termout on
12:21:31 portal@ >alter trigger DB_TR_PUNCHDATASAP disable
12:21:53 2 /

Trigger altered.

real: 16
12:21:54 portal@ >spo off

12:29:27 ipcltos@ >Input truncated to 14 characters
set termout on
12:29:27 ipcltos@ >INSERT INTO ipcltos.PunchDataSap
12:29:41 2 SELECT -1, PUNCHDATE, PUNCHTIME, INOUT, MACHINEID, LOCCODE, PUNCHST, CMPLXCD, SAPUPFLG, ERRMSG, SRNO
12:29:41 3 FROM PunchDataSap WHERE 1=1 AND EmpCode = 16207625
12:29:41 4 AND ROWNUM < 11
12:29:41 5 /

10 rows created.

real: 16
12:29:42 ipcltos@ >roll
Rollback complete.
12:29:44 ipcltos@ >
12:31:01 ipcltos@ >

12:31:02 ipcltos@ >SELECT Trigger_Name, Trigger_Type, Triggering_Event, Table_Owner, Table_Name, Description
12:31:12 2 FROM User_Triggers
12:31:12 3 WHERE Table_Name = UPPER ('PunchDataSap')
12:31:12 4 /

TRIGGER_NAME TRIGGER_TYPE
------------------------------ ----------------
TRIGGERING_EVENT
--------------------------------------------------------------------------------
TABLE_OWNER TABLE_NAME
------------------------------ ------------------------------
DESCRIPTION
--------------------------------------------------------------------------------
DB_TR_PUNCHDATASAP BEFORE EACH ROW
INSERT
IPCLTOS PUNCHDATASAP
"IPCLTOS"."DB_TR_PUNCHDATASAP" BEFORE INSERT ON "IPCLTOS"."PUNCHDATASAP" FOR EAC
H ROW


real: 31
12:31:13 ipcltos@ >desc PunchDataSap
Name Null? Type
------------------------------- -------- ----
EMPCODE NOT NULL NUMBER(8)
PUNCHDATE NOT NULL DATE
PUNCHTIME NOT NULL VARCHAR2(6)
INOUT VARCHAR2(1)
MACHINEID NUMBER(4)
LOCCODE VARCHAR2(3)
PUNCHST VARCHAR2(1)
CMPLXCD VARCHAR2(2)
SAPUPFLG VARCHAR2(1)
ERRMSG VARCHAR2(40)
SRNO NUMBER(10)

12:32:12 ipcltos@ >@InD11
12:32:29 ipcltos@ >COLUMN table_name format A20
12:32:29 ipcltos@ >COLUMN index_name format A20
12:32:29 ipcltos@ >COLUMN index_type format A20
12:32:29 ipcltos@ >COLUMN column_name format A20
12:32:29 ipcltos@ >break ON table_name skip ON index_name skip
12:32:29 ipcltos@ >
12:32:29 ipcltos@ >SELECT I.Table_Name Table_Name, I.Index_Name Index_Name, Uniqueness, Index_Type,
12:32:29 2 Column_name
12:32:29 3 FROM user_indexes I, user_ind_columns C
12:32:29 4 WHERE I.index_name = C.index_name (+)
12:32:29 5 AND I.Table_name LIKE UPPER ('&Tbl_Nam')
12:32:29 6 ORDER BY I.Table_name, I.Index_Name, C.Column_Position
12:32:29 7
12:32:31 ipcltos@ >/
Enter value for tbl_nam: PunchDataSap
old 5: AND I.Table_name LIKE UPPER ('&Tbl_Nam')
new 5: AND I.Table_name LIKE UPPER ('PunchDataSap')

TABLE_NAME INDEX_NAME UNIQUENES INDEX_TYPE
-------------------- -------------------- --------- --------------------
COLUMN_NAME
--------------------
PUNCHDATASAP PK_PUNCHDATASAP UNIQUE NORMAL
EMPCODE

UNIQUE NORMAL
PUNCHDATE

UNIQUE NORMAL
PUNCHTIME


real: 62
12:32:41 ipcltos@ >spo off

(8)

12:33:09 portal@ >desc PunchDataSap
Name Null? Type
------------------------------- -------- ----
EMPCODE NUMBER(8)
PUNCHDATE DATE
PUNCHTIME VARCHAR2(6)
INOUT VARCHAR2(1)
MACHINEID NUMBER(4)
LOCCODE VARCHAR2(3)
PUNCHST VARCHAR2(1)
CMPLXCD VARCHAR2(2)
SAPUPFLG VARCHAR2(1)
ERRMSG VARCHAR2(40)
SRNO NUMBER(10)

12:33:17 portal@ >@InD11
12:33:21 portal@ >COLUMN table_name format A20
12:33:21 portal@ >COLUMN index_name format A20
12:33:21 portal@ >COLUMN index_type format A20
12:33:21 portal@ >COLUMN column_name format A20
12:33:21 portal@ >break ON table_name skip ON index_name skip
12:33:21 portal@ >
12:33:21 portal@ >SELECT I.Table_Name Table_Name, I.Index_Name Index_Name, Uniqueness, Index_Type,
12:33:21 2 Column_name
12:33:21 3 FROM user_indexes I, user_ind_columns C
12:33:21 4 WHERE I.index_name = C.index_name (+)
12:33:21 5 AND I.Table_name LIKE UPPER ('&Tbl_Nam')
12:33:21 6 ORDER BY I.Table_name, I.Index_Name, C.Column_Position
12:33:21 7 /
Enter value for tbl_nam: PunchDataSap
old 5: AND I.Table_name LIKE UPPER ('&Tbl_Nam')
new 5: AND I.Table_name LIKE UPPER ('PunchDataSap')

no rows selected

real: 16
12:33:27 portal@ >SELECT Trigger_Name, Trigger_Type, Triggering_Event, Table_Owner, Table_Name, Description
12:33:36 2 FROM User_Triggers
12:33:36 3 WHERE Table_Name = UPPER ('PunchDataSap')
12:33:36 4 /

TRIGGER_NAME TRIGGER_TYPE
------------------------------ ----------------
TRIGGERING_EVENT
--------------------------------------------------------------------------------
TABLE_OWNER TABLE_NAME
------------------------------ --------------------
DESCRIPTION
--------------------------------------------------------------------------------
DB_TR_PUNCHDATASAP BEFORE EACH ROW
INSERT
IPCLTOS PUNCHDATASAP
"PORTAL"."DB_TR_PUNCHDATASAP" BEFORE INSERT ON "IPCLTOS"."PUNCHDATASAP" FOR EACH
ROW


real: 63
12:33:37 portal@ >spo off

Exp / Imp & Trigger

Yogesh Purabiya, March 06, 2007 - 2:09 am UTC

I had asked a query in the last review (23-Dec-2006).
Since in was quite huge, I split it in 2 reviews.

The main point is that, after EXPort from userA and IMPort in (/ to) userB, the userB.User_Triggers.Table_Owner for one trigger shows "userA", though it shows "userB" for all other triggers (new IMPorted tables as well).
Tom Kyte
March 06, 2007 - 11:02 am UTC

can you reproduce a small test case for us, it helps to see what "inputs" to export there were in the database in the first place.

Exp / Imp & Trigger Table Owner

Yogesh Purabiya, March 09, 2007 - 5:01 am UTC

I understand it is too difficult to go through huge examples when you alone are attending so many queries.

This type of problems do not occur frequently, only rarely.

I could not get a small example; so we need to wait for such opportunity.

Thanks for as usual.

line substr

Gabriel Schor, May 09, 2007 - 1:19 pm UTC

Hello Tom,

I was implementing your who_called_me function and I was getting some errors. After some debuging I replaced lineno := to_number(substr( line, 13, 6 )); with lineno := to_number(substr( line, 13, 7 )); and it works now. I was really happy cause I thought I found a bug in your code. Then I got back to the post and saw your replies to other people that thought the same thing as me. Naive us, of course there is no bug in Tom's code ;)

Can you please explain why does the line format vary?

Thank you very much,

Who called me- for View names?

A reader, August 11, 2010 - 7:37 pm UTC

Hi Tom,
I was wondering if there is a way to find the name of the view that calls a program. I have a lot of views that have a pipeline function in them . one of the parameter of the function is the view name to ensure we know which view called it, in event of an error.
Is there any way to dynamically pass the caller view name into the function(which is actually in the view text?). I tried something with RLS, but was wondering if there's a simpler way.

thank you very much!

Tom Kyte
August 19, 2010 - 12:15 am UTC

not that I know of since the VIEW is from the SQL layer and the call stack is a PL/SQL layer thing. The view layer isn't really "code", it isn't considered in the call stack.

What a Shame!

Nirvana, July 12, 2013 - 11:52 pm UTC

Tom,

The so called number 1 database doesnot have easy way to find the current procedure name?

What a shame!

Shame shame puppy shame!

At least give some easy online option to find the current package.procedure name.


Tom Kyte
July 16, 2013 - 4:28 pm UTC

owa_util.who_called_me


has existed for many many many years. pretty simple to create a who_am_i that just returns who_called_me.


also since 9i:


ops$tkyte%ORA11GR2> create or replace procedure p
  2  as
  3  begin
  4          dbms_output.put_line( 'I am ' || $$PLSQL_UNIT || ' on ' || $$PLSQL_LINE);
  5  end;
  6  /

Procedure created.

ops$tkyte%ORA11GR2> exec p
I am P on 4

PL/SQL procedure successfully completed.




and newly added:

http://asktom.oracle.com/Misc/12c-utlcallstack.html


hmmmm


shame on your for not reading the documentation?

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