Will the following code lead to a deadlock or should it work without any problem? I’ve got something similar and it’s working but I didn’t think it would. I thought the parent procedure’s lock would have resulted in a deadlock for the child procedure but it doesn’t seem to be.
If it works, why? My guess is that the nested FOR UPDATE is not running into a deadlock because it’s smart enough to realize that it is being called by the same procedure that has the current lock.
Would this be a deadlock if FOO_PROC was not a nested procedure?
DECLARE
FOO_PROC(c_someName VARCHAR2) as
cursor c1 is select * from awesome_people where person_name = c_someName FOR UPDATE;
BEGIN
open c1;
update awesome_people set person_name = UPPER(person_name);
close c1;
END FOO_PROC;
cursor my_cur is select * from awesome_people where person_name = 'John Doe' FOR UPDATE;
BEGIN
for onerow in c1 loop
FOO_PROC(onerow.person_name);
end loop;
END;
It won’t cause a deadlock. THat can only happen when two sessions update the same row because they are employing an optimistic locking strategy. Here is what happens
Some test data:
This is your anonymous (with corrected sybtax):.
And this is the outcome
SQL> select * from t23
2 /
So does it succeed? Because the FOR UPDATE is a session level lock. The two locks are issued from the same session so Oracle is smart enough to resolve them without contention. Howver if you were to do something like declare an PRAGMA AUTONOMOUS_TRANSACTION in FOO_PROC() it would hurl
The fact that two calls to FOR UPDATE in the same session do not not fail in this manner is an important piece of architectural design. It is not possible to tell whether a procedure issues a lock without looking at the source code. So when PROC_A() calls PROC_B() it has no idea whether that procedure issues a lock. But PROC_A() can issues its own lock, confident that this action will not cause PROC_B() to fail. This is a good thing, because it upholds the Law of Demeter and reduces coupling.
Of course, your scenario is artificial, and would be rejected as bad practice in a code review, but that is a different issue!
edit
Are you sure? The AUTONOMOUS_TRANSACTION pragma means precisely that FOO_PROC() runs in its own discrete session, and so fails to get a lock:
(I added some DBMS_OUTPUT statements to show what’s happening).
I meant having a loop driving off a SELECT statement calling another program which selects from the same table. Indeed, which selects the very same row. Generally speaking, we should avoid doing unnecessary work. You already have the row: why read it again?