Enhancement filed
Duke Ganote, February 15, 2006 - 11:28 am UTC
As always, a true Jedi
Khalid, February 15, 2006 - 12:42 pm UTC
Thanks for the two scenarios where you need the locks.
I have a need for a lock (serialization) inside a trigger myself for a very very short duration, but I don't know how to do it, would you please look at my problem?
I need a serialization around two count(*)'s, but select for update won't work in my case. I need this inside a trigger.
The error I get is
Select count(*) from my_table for update won't work.
ERROR at line 1:
ORA-01786: FOR UPDATE of this query expression is not allowed
Here is my trigger, I ha
create or replace trigger qrs.room_full_alert_iufer
after insert or update on qrs.rooms
for each row
declare
v_rm_count number;
v_chs_count number;
begin
if inserting or updating then
-- Need some serialization/some locking mechanism here
select count(*) into v_rm_count from qrs.prtcpnt_rooms a
where a.room__id = :new.room__id;
select count(*) into v_chs_count from qrs.room_held_seats a
where a.room_id = :new.room_id;
if :new.max_enrolment > (v_rm_count + v_chs_count) then
v_full := 'N';
else
v_full := 'Y';
end if;
-- End serialization here
exception
when others then
dbms_output.put_line(sqlcode || ' ' || sqlerrm);
raise;
end qrs.room_full_alert_iufer;
Thanks again in advance.
February 15, 2006 - 1:17 pm UTC
there must be a parent table somewhere with a primary key of room_id right?
select for update THAT ROW.
You will therefore serialize at the ROOM_ID level.
And just make sure your application runs in read committed isolation only :)
you need to serialize your transaction. not just that "critical section"
and please, erase that when others, it is less than pointless. It is less than useful. The only thing it does is hide from the client where the actual error took place - nothing else.
select count(*) into v_rm_count from qrs.prtcpnt_rooms a
where a.room__id = :new.room__id;
select count(*) into v_chs_count from qrs.room_held_seats a
where a.room_id = :new.room_id;
if :new.max_enrolment > (v_rm_count + v_chs_count) then
could be
select case when :new.max_enrolment > cnt
then 'N'
else 'Y'
end into whatever
from (select sum(cnt)
from (select count(*) cnt from t1 where ...
union all
select count(*) cnt from t2 where ... )
)
My question was answered, and I got something more
Khalid, February 15, 2006 - 1:53 pm UTC
Yes there is a parent table, where room_id is the primary key. I will test my code with the solution you have provided.
Thanks for the reminder on the 'when others ... ' also, I will try not to do error handling/propogation like that again.
February 15, 2006 - 2:13 pm UTC
no need to thanks on the "when others"
it is right up on there on the list of automatic knee jerk responses - right after "use bind variables"
Where shall I asktom?
Khalid, February 15, 2006 - 4:39 pm UTC
February 15, 2006 - 9:52 pm UTC
well, if you have a question about the contents of that question, the most logical place to ask it would be - that question.
how could it be OT (off topic?) if it is about that question/answer thread?
Solution works, but I am missing the concept.
Khalid, February 16, 2006 - 12:23 pm UTC
You gave me a great solution, but I am somehow still not getting this concept clear. I knew you discuss some of this in your book 1, I read it again, but still ...
Notice you constructed a single single SQL statement for me, so the data should be read consistent for the entire life time of this statement, therefore my question to you is:
What confuses me is the following:-
a) "And just make sure your application runs in read committed isolation only :)"
b) 'you need to serialize your transaction. not just that "critical section"'
So the below solution serializes by virtue of wrapping the entire critical section within a single statement?
and I am assuming Oracle provides REPEATABLE READ by default will give me the serialization at the statement level automatically. There is nothing more than that I need.
But setting READ COMMITTED ONLY as you say, I have to provide serialization not just for the statement but for the entire duration of the transaction.
-- THE SQL YOU GAVE ME ALL DONE IN 1 STATEMENT ------
-- WHICH I THINK IS SUFFICIENT BY ITSELF ------
select case when :new.max_enrolment > cnt
then 'N'
else 'Y'
end into whatever
from (select sum(cnt)
from (select count(*) cnt from t1 where ...
union all
select count(*) cnt from t2 where ... )
)
February 17, 2006 - 1:16 pm UTC
when you run in serializable, all queries you run will run "as of the time the transaction began", you won't SEE ANY CHANGES made by other concurrent sessions.
You need to SELECT FOR UPDATE the single PARENT record (that will serialize)
and then you can read the other table(s).
Will do that
Khalid, February 17, 2006 - 10:47 pm UTC