Subject | FOR SELECT resultset changed during update statement |
---|---|
Author | raivis83 |
Post date | 2010-12-13T18:02:04Z |
Hello all!
I have noticed one problem with FOR SELECT statement in pl/sql procedure. Correct me if I am wrong but as far as I know ResultSet returned by SELECT statement should remain unchanged while looping through it. But it isn't. Calling update statement in the loop changes resultset returned by FOR SELECT statement. I tried this on firebird 2.1 clasic and firebird 2.5 superclasic servers.
Here is DDL for testing:
-------------------------------------------------------------------------------------------------
--Table
----------
SET SQL DIALECT 3;
CREATE TABLE TRV_TEMP (
ID INTEGER,
NAME VARCHAR(20),
TYP VARCHAR(5),
CNT INTEGER,
IS_DONE SMALLINT
);
----------
--Procedure
----------
SET TERM ^ ;
create or alter procedure PRV_TT
AS
--
declare variable id integer;
declare variable counter int default 0;
declare variable typ varchar(5);
begin
for select t.id, t.typ
from trv_temp t
where
t.is_done = 0
into :id, :typ
do
begin
-- Doing some calculations here, like calling another
-- preocedure with the data fetched from current record and updating records.
-- To keep it simple, I'll just update field CNT with the current value of
-- variable counter
update trv_temp set cnt = :counter where id = :id;
-- Seting is_done to 1 for all the records with selected typ
update trv_temp
set is_done = 1
where typ = :typ;
counter = counter + 1;
end
end^
SET TERM ; ^
GRANT SELECT,UPDATE ON TRV_TEMP TO PROCEDURE PRV_TT;
GRANT EXECUTE ON PROCEDURE PRV_TT TO SYSDBA;
----------
--Testing data
----------
insert into trv_temp (id, name, typ, cnt, is_done) values (1, 'N1', 'A', -1, 0)
insert into trv_temp (id, name, typ, cnt, is_done) values (2, 'N2', 'A', -1, 0)
insert into trv_temp (id, name, typ, cnt, is_done) values (3, 'N3', 'B', -1, 0)
insert into trv_temp (id, name, typ, cnt, is_done) values (4, 'N4', 'B', -1, 0)
-------------------------------------------------------------------------------------------------
SELECT * FROM TRV_TEMP "BEFORE" executing procedure PRV_TT:
ID NAME IS_DONE TYP CNT
------------------------------------
1 N1 0 A -1
2 N2 0 A -1
3 N3 0 B -1
4 N4 0 B -1
SELECT * FROM TRV_TEMP "AFTER" executing procedure PRV_TT:
ID NAME IS_DONE TYP CNT
------------------------------------
1 N1 1 A 0
2 N2 1 A -1
3 N3 1 B 1
4 N4 1 B -1
SHOULD BE:
ID NAME IS_DONE TYP CNT
------------------------------------
1 N1 1 A 0
2 N2 1 A 1
3 N3 1 B 2
4 N4 1 B 3
I have noticed one problem with FOR SELECT statement in pl/sql procedure. Correct me if I am wrong but as far as I know ResultSet returned by SELECT statement should remain unchanged while looping through it. But it isn't. Calling update statement in the loop changes resultset returned by FOR SELECT statement. I tried this on firebird 2.1 clasic and firebird 2.5 superclasic servers.
Here is DDL for testing:
-------------------------------------------------------------------------------------------------
--Table
----------
SET SQL DIALECT 3;
CREATE TABLE TRV_TEMP (
ID INTEGER,
NAME VARCHAR(20),
TYP VARCHAR(5),
CNT INTEGER,
IS_DONE SMALLINT
);
----------
--Procedure
----------
SET TERM ^ ;
create or alter procedure PRV_TT
AS
--
declare variable id integer;
declare variable counter int default 0;
declare variable typ varchar(5);
begin
for select t.id, t.typ
from trv_temp t
where
t.is_done = 0
into :id, :typ
do
begin
-- Doing some calculations here, like calling another
-- preocedure with the data fetched from current record and updating records.
-- To keep it simple, I'll just update field CNT with the current value of
-- variable counter
update trv_temp set cnt = :counter where id = :id;
-- Seting is_done to 1 for all the records with selected typ
update trv_temp
set is_done = 1
where typ = :typ;
counter = counter + 1;
end
end^
SET TERM ; ^
GRANT SELECT,UPDATE ON TRV_TEMP TO PROCEDURE PRV_TT;
GRANT EXECUTE ON PROCEDURE PRV_TT TO SYSDBA;
----------
--Testing data
----------
insert into trv_temp (id, name, typ, cnt, is_done) values (1, 'N1', 'A', -1, 0)
insert into trv_temp (id, name, typ, cnt, is_done) values (2, 'N2', 'A', -1, 0)
insert into trv_temp (id, name, typ, cnt, is_done) values (3, 'N3', 'B', -1, 0)
insert into trv_temp (id, name, typ, cnt, is_done) values (4, 'N4', 'B', -1, 0)
-------------------------------------------------------------------------------------------------
SELECT * FROM TRV_TEMP "BEFORE" executing procedure PRV_TT:
ID NAME IS_DONE TYP CNT
------------------------------------
1 N1 0 A -1
2 N2 0 A -1
3 N3 0 B -1
4 N4 0 B -1
SELECT * FROM TRV_TEMP "AFTER" executing procedure PRV_TT:
ID NAME IS_DONE TYP CNT
------------------------------------
1 N1 1 A 0
2 N2 1 A -1
3 N3 1 B 1
4 N4 1 B -1
SHOULD BE:
ID NAME IS_DONE TYP CNT
------------------------------------
1 N1 1 A 0
2 N2 1 A 1
3 N3 1 B 2
4 N4 1 B 3