The documentation on cursors states:
If neither WITHOUT HOLD nor WITH HOLD is specified, WITHOUT HOLD is the default […] If WITH HOLD is specified and the transaction that created the cursor successfully commits, the cursor can continue to be accessed by subsequent transactions in the same session
In my below example I do not specify WITH HOLD
and still, the anyonymous block successfully copies all 1000 rows from table a
to table b
:
create table a (c) as SELECT * FROM generate_series(1, 1000);
create table b as select * from a limit 0;
do $$
DECLARE
_rec RECORD;
BEGIN
FOR _rec IN
select c from a
LOOP
insert into b values (_rec.c);
commit;
END LOOP;
END;
$$
select * from b;
-- exactly like table a
select count(*) from b;
-- 1000
Why does the example work in the way it does? It seems it behaves like if WITH HOLD
was set? So is what happening here the same as if WITH HOLD
was set, which is that upon the first commit a snapshot of the results of the cursor is made and that snapshot is used for the remainder of the loops? Or is something else going on that allows the cursor to see the data as it was when the anonymous block was started? Or does it see new data after each commit (can’t believe that is the case)?
2
Answers
You should specifically declare the cursor with WITH HOLD in order to get the desired behavior of a cursor that maintains its location between commits. Try this code, I have added the functionality into it.
Hope it solves your issue 🙂
Your link is for DECLARE, which you never use (in the cursor sense) in your code. You are using automatic plpgsql cursors, which are obviously related to but not identical to SQL cursors. From the relevant doc for that: