Parallel TID Range Scan returns wrong results on rescan

From: Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, David Rowley <dgrowleyml(at)gmail(dot)com>
Subject: Parallel TID Range Scan returns wrong results on rescan
Date: 2026-10-15 19:54:12
Message-ID: CAN4CZFOoyCQE483YVGg07_Vr2MjFCTiCLUHUAFCwKqJAE=PN6w@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello

I found a bug in parallel TID range can: if the gather above it gets
rescanned with different TID bounds, rows can go missing.

A simple way to reproduce it:

CREATE TABLE t (id int, pad text) WITH (fillfactor = 10);
INSERT INTO t SELECT i, repeat('x', 100) FROM generate_series(1, 200) i;
SET parallel_setup_cost = 0;
SET parallel_tuple_cost = 0;
SET min_parallel_table_scan_size = 0;
SET max_parallel_workers_per_gather = 4;

SELECT r.lo, (SELECT count(*) FROM t WHERE ctid >= (SELECT r.lo)) c
FROM (VALUES ('(30,0)'::tid), ('(10,0)'), ('(0,0)')) r(lo);

This should return 50, 150 and 200 (that's also what 18 returns,
without the parallel scan), but master and 19rc1 return 50 for all 3
rows.

The cause:

phs_startblock and phs_numblock in ParallelBlockTableScanDesc are set
by whichever participant calls
table_block_parallelscan_startblock_init() first, but
table_block_parallelscan_reinitialize() only resets phs_nallocated. So
every rescan scans the block range of the first execution, and the
per-tuple TID check then throws away anything outside the new range.

The attached patch resets both fields to InvalidBlockNumber in
table_block_parallelscan_reinitialize(), and adds a test that fails
without the fix.

Attachment Content-Type Size
v1-0001-Fix-Parallel-TID-Range-Scan-rescans-with-a-differ.patch application/octet-stream 4.5 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Baji Shaik 2026-10-15 19:58:50 Re: [PATCH] Doc fix for autovacuum_max_parallel_workers
Previous Message Manu 2026-10-15 19:49:08 Re: ZSTD TOAST compression, and an extensible compression method encoding