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: v1-0001-Fix-Parallel-TID-Range-Scan-rescans-with-a-differ.patch
Description: Binary data

Reply via email to