Fix incorrect logic in HaveRegisteredOrActiveSnapshot().

This function gave the wrong answer when there's more than one
RegisteredSnapshots entry, whether or not any of them is the
CatalogSnapshot.  This leads to assertion failure in some scenarios
involving fetching toasted data using a cursor.  (As per discussion,
I'm dubious that this is the right contract to be enforcing at all;
but it surely doesn't help to be enforcing it incorrectly.)

Fetching toasted data using a cursor is evidently under-tested,
so add a test case too.

Per report from Erik Rijkers.  This is new code, so no need for
back-patch.

Discussion: https://postgr.es/m/dc9dd229-ed30-6c62-4c41-d733ffff776b@xs4all.nl
This commit is contained in:
Tom Lane 2022-04-16 16:04:50 -04:00
parent a17fd67d2f
commit 9f4f0a0dad
3 changed files with 52 additions and 3 deletions

View File

@ -1646,11 +1646,11 @@ HaveRegisteredOrActiveSnapshot(void)
* removed at any time due to invalidation processing. If explicitly
* registered more than one snapshot has to be in RegisteredSnapshots.
*/
if (pairingheap_is_empty(&RegisteredSnapshots) ||
!pairingheap_is_singular(&RegisteredSnapshots))
if (CatalogSnapshot != NULL &&
pairingheap_is_singular(&RegisteredSnapshots))
return false;
return CatalogSnapshot == NULL;
return !pairingheap_is_empty(&RegisteredSnapshots);
}

File diff suppressed because one or more lines are too long

View File

@ -581,3 +581,27 @@ declare c2 scroll cursor for select generate_series(1,3) as g;
fetch all in c2;
fetch backward all in c2;
rollback;
-- Check fetching of toasted datums via cursors.
begin;
-- Other compression algorithms may cause the compressed data to be stored
-- inline. Use pglz to ensure consistent results.
set default_toast_compression = 'pglz';
create table toasted_data (f1 int[]);
insert into toasted_data
select array_agg(i) from generate_series(12345678, 12345678 + 1000) i;
declare local_portal cursor for select * from toasted_data;
fetch all in local_portal;
declare held_portal cursor with hold for select * from toasted_data;
commit;
drop table toasted_data;
fetch all in held_portal;
reset default_toast_compression;