Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Table Mutating

Status
Not open for further replies.

TLiberty

Programmer
Nov 22, 1999
27
US
I'm learning oracle and have a problem understanding the message &quot;Table: Client mutating... can not see trigger or function...&quot;<br>
<br>
Before i state my question in detail (i know you guys already understand the problem from the message above)<br>
<br>
Entities of client<br>
Client_number (primary key)<br>
Tech_number<br>
FName<br>
LName<br>
<br>
Entities of UpdateLog<br>
UpdateID (sequence, primary key)<br>
Comments<br>
Client_Number (foreign key)<br>
DateUpdated<br>
UpdatedBY (default log on user)<br>
<br>
Packages Procedure<br>
InsertIntoUpdateLog( *parameters )<br>
*Same as UpdateLog entities<br>
<br>
In trigger i have <br>
<br>
PKG_NAME.INSERTINTOUPDATELOG( UPDATEID.NEXTVAL,strCOMMENTS, SYSDATE, USER);<br>
<br>
When i insert a record in client it always give the error stated above. What am I doing wrong? Please help.
 
Do you get an Oracle Error Message with a number?<br>
<br>
-ml<br>
<p>Mike Lacey<br><a href=mailto:Mike_Lacey@Cargill.Com>Mike_Lacey@Cargill.Com</a><br><a href= Cargill's Corporate Web Site</a><br>
 
The mutating table error occurs when you try and perform a DML operation on the same table on which a row level trigger is firing.<br>
I suspect that you have a trigger being fired for each row that is inserted into your client table, and that your packaged procedure is trying to do a select on client information.<br>
It may be that you could pass in the information needed by the procedure - i.e. using :NEW.column_name_of_client_info_that_proc_needs to refer to the required value in the newly inserted row.<br>
Have a look for any DML that the procedure may be doing involving the client table; if you're still stuck, if you could give the heading of the trigger definition that would help.
 
yaffle,<br>
<br>
This is the trigger attached to client and below is the package body:<br>
<br>
I'm not near my pc right now, but the trigger is similar to this:<br>
<br>
CREATE TRIGGER TAI_UPDATELOG <br>
AFTER INSERT ON CLIENT <br>
FOR EACH ROW <br>
REFERENCING OLD AS OLD, NEW AS NEW<br>
BEGIN<br>
-- ALSO, I DIDN'T MENTION I HAVE ANOTHER FIELD<br>
-- IN CLIENTS CALLED TECH_NUMBER<br>
<br>
PKG_UPDATELOG_ROUTINES.INSERTINTOUPDATELOG(SEQUENCE_UPDATEID.NEXTVAL, :NEW.CLIENT_NUMBER, SYSDATE, USER, :NEW.TECH_NUMBER, 'JUST A TEST INFORMATION');<br>
<br>
END TAI_UPDATELOG;<br>
<br>
<br>
Package body,<br>
CREATE OR REPLACE PACKAGE BODY PKG_UPDATELOG_ROUTINES AS<br>
... -- OTHER ROUTINES NOT INTERESTED IN THOSE<br>
<br>
PROCEDURE INSERTINTOUPDATELOG(UPDID IN NUMBER, CLIENTNO IN NUMBER, DATEIN IN DATE, USERIN IN VARCHAR2, TECHNO IN NUMBER, COMMENTSIN IN VARCHAR2) AS <br>
BEGIN<br>
INSERT INTO UPDATE_LOG VALUES (UPID, CLIENTNO, DATEIN, USERIN, TECHNO, COMMENTSIN);<br>
COMMIT;<br>
END INSERTINTOUPDATELOG;<br>
END PKG_UPDATELOG_ROUTINES;<br>
<br>
Thanks alot.
 
I'm not sure that the commit statement in your procedure will work properly when invoked from a trigger; you could try taking that out and leaving the transaction processing around your client insert to handle it.<br>
Alternatively, do you perhaps have a further trigger on the update_log table ?<br>
Failing that, I think the full error text is probably needed.
 
I don't think you can do this - look at your code - if the DBMS did as you tell it - it would go up its own a**s real quick. That's a recursive thing you've got there and Oracle just won't let you do it. I would guess that it you comment out the INSERT INTO UPDATE_LOG statement it runs just fine?<br>
<br>
Mike<br>
<p>Mike Lacey<br><a href=mailto:Mike_Lacey@Cargill.Com>Mike_Lacey@Cargill.Com</a><br><a href= Cargill's Corporate Web Site</a><br>
 
I don't think there's any recursion going on here. There's nothing wrong with using a trigger to automatically insert a row into a table when one is added to a different table; if both table have triggers accessing each other perhaps.<br>
Having had a look at the code again another thing occurs to me - I'm not sure about the reference to SEQUENCE_UPDATEID.NEXTVAL as I think sequences are restricted to use in certain SQL statements. Try putting it in the values clause of the insert statement in the procedure, rather than passing it in.
 
The actual error messages are:<br>
<br>
ORA-04091: table LIBTECH.CLIENT is mutating, trigger/function may not see it.<br>
0RA-06512: at LIBTECH.PKG_PILOTSERVICES line 6<br>
ORA-06512: at LIBTECH.TAI_UPDATELOG line 2<br>
ORA-04088: error during execution of trigger 'LIBTECH.TAI_UPDATELOG'.<br>
<br>
Sample code again from my laptop (I have Oracle Navigator):<br>
Trigger <br>
CREATE OR REPLACE TRIGGER TAI_UPDATELOG<br>
AFTER INSERT ON CLIENT <br>
REFERENCING OLD AS OLD NEW AS NEW<br>
BEGIN<br>
PKG_PILOTSERVICES.INSERTINTOUPDATELOG:)NEW.TECH_NUMBER, :NEW.CLIENT_NUMBER, USER, 'JUST A TEST');<br>
END;<br>
<br>
PACKAGE BODY PKG_PILOTSERVICES IS -- body (hidden part)<br>
-- private type and object declarations<br>
-- subprogram bodies<br>
PROCEDURE INSERTINTOUPDATELOG(TechNo IN VARCHAR2, ClientNo IN NUMBER, UpdateBy IN VARCHAR2 DEFAULT USER, CommentsIn IN VARCHAR2) IS <br>
BEGIN<br>
INSERT INTO UPDATELOG VALUES (UPDATEID.NEXTVAL, TechNo, ClientNo, SYSDATE, UpdateBy, CommentsIn);<br>
END INSERTINTOUPDATELOG;<br>
END;<br>
<br>
I moved the commit like you told me to, but no avail.
 
Curiouser and curiouser... I haven't actually got access to Oracle at the moment on my current project, which make things a bit tricky to check, but:<br>
I notice the FOR EACH ROW is missing from your code now - I'd expect this to give a compile error, rather than runtime, but would make the :NEW reference invalid in any case.<br>
Is it possible that there are any other triggers around firing on CLIENT or UPDATELOG ? Check the all_triggers system view.<br>
You could try dropping and recompiling the trigger and package too - to ensure your latest versions are being run.<br>

 
Not able to get to Oracle, can get to the technet web page ;-)<br>
<br>
ORA-04091: table name is mutating, trigger/function may not see it<br>
<br>
Cause: A trigger or a user-defined PL/SQL function that is referenced in the statement attempted to query or modify a table that was in the middle of being modified by the statement that fired the trigger. <br>
<br>
Action: Rewrite the trigger or function so it does not read the table. <br>
<br>
<br>
Valid SQL Statements in Trigger Bodies:<br>
The body of a trigger can contain DML SQL statements. It can also contain SELECT statements, but they must be SELECT... INTO... statements or the SELECT statement in the definition of a cursor). <br>
DDL statements are not allowed in the body of a trigger. Also, no transaction control statements are allowed in a trigger. The commands ROLLBACK, COMMIT, and SAVEPOINT cannot be used. <br>
Note: A procedure called by a trigger cannot execute the above transaction control statements because the procedure executes within the context of the trigger body. <br>
<br>
<br>
Mutating and Constraining Tables:<br>
A mutating table is a table that is currently being modified by an UPDATE, DELETE, or INSERT statement, or a table that might need to be updated by the effects of a declarative DELETE CASCADE referential integrity constraint. A constraining table is a table that a triggering statement might need to read either directly, for a SQL statement, or indirectly, for a declarative referential integrity constraint. A table is mutating or constraining only to the session that issued the statement in progress. <br>
Tables are never considered mutating or constraining for statement triggers unless the trigger is fired as the result of a DELETE CASCADE. <br>
For all row triggers, or for statement triggers that were fired as the result of a DELETE CASCADE, there are two important restrictions regarding mutating and constraining tables. These restrictions prevent a trigger from seeing an inconsistent set of data. <br>
The SQL statements of a trigger cannot read from (query) or modify a mutating table of the triggering statement.<br>
The statements of a trigger cannot change the PRIMARY, FOREIGN, or UNIQUE KEY columns of a constraining table of the triggering statement. There is an exception to this restriction; BEFORE ROW and AFTER ROW triggers fired by a single row INSERT to a table do not treat that table as mutating or constraining. Note that INSERT statements that may involve more than one row, such as INSERT INTO emp SELECT . . ., are not considered single row inserts, even if they only result in one row being inserted. <br>
<br>
If you need to update a mutating or constraining table, you could use a temporary table, a PL/SQL table, or a package variable to bypass these restrictions. For example, in place of a single AFTER row trigger that updates the original table, resulting in a mutating table error, you may be able to use two triggers-an AFTER row trigger that updates a temporary table, and an AFTER statement trigger that updates the original table with the values from the temporary table. <br>
<br>
<br>
My theory is that the foreign key on the UPDATELOG table makes it a constraining table for the CLIENT insert, so to work around it you'd need a temporary table that your client trigger inserts to instead of calling your procedure, with a statement level after insert trigger on it that called your procedure.<br>
Perhaps better would be to change your trigger to be a statement level trigger with a cursor of the form:<br>
select * from client c<br>
where not exists<br>
(select null from updatelog u<br>
where u.client_number = c.client_number);<br>
For each row returned by the cursor you could then call your procedure.<br>

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top