We've recently upgraded from Oracle 10 to Oracle 11.2. After upgrading, I started seeing a mutating table error caused by a function rather than a trigger (which I've never come across before). It's old code that worked in prior versions of Oracle.
Here's a scenario that will cause the error:
create table mutate (
x NUMBER,
y NUMBER
);
insert into mutate (x, y)
values (1,2);
insert into mutate (x, y)
values (3,4);
I've created two rows. Now, I'll double my rows by calling this statement:
insert into mutate (x, y)
select x + 1, y + 1
from mutate;
This isn't strictly necessary to duplicate the error, but it helps with my demonstration later. So the contents of the table now look like this:
X,Y
1,2
3,4
2,3
4,5
All is well. Now for the fun part:
create or replace function mutate_count
return PLS_INTEGER
is
v_dummy PLS_INTEGER;
begin
select count(*)
into v_dummy
from mutate;
return v_dummy;
end mutate_count;
/
I've created a function to query my table and return a count. Now, I'll combine that with an INSERT statement:
insert into mutate (x, y)
select x + 2, y + 2
from mutate
where mutate_count() = 4;
The result? This error:
ORA-04091: table MUTATE is mutating, trigger/function may not see it
ORA-06512: at "MUTATE_COUNT", line 6
So I know what causes the error, but I am curious as to the why. Isn't Oracle performing the SELECT, retrieving the result set, and then performing a bulk insert of those results? I would only expect a mutating table error if records were already being inserted before the query finished. But if Oracle did that, wouldn't the earlier statement:
insert into mutate (x, y)
select x + 1, y + 1
from mutate;
start an infinite loop?
UPDATE:
Through Jeffrey's link I found this in the Oracle docs:
By default, Oracle guarantees statement-level read consistency. The set of data returned by a single query is consistent with respect to a single point in time.
There's also a comment from the author in his post:
One could argue why Oracle doesn't ensure this 'statement-level read consistency' for repeated function calls that appear inside a SQL statement. It could be considered a bug as far as I'm concerned. But this is the way it currently works.
Am I correct in assuming that this behavior has changed between Oracle versions 10 and 11?