Fix hash index scans that start during a bucket split. A hash index scan whose target bucket is still being populated by a split must read both buckets of the split: forward scans read the bucket being populated (skipping the tuples that the split copied there) and then the bucket being split, and backward scans read them in the opposite order. _hash_readnext and _hash_readprev make the transition from the first bucket to the second, but _hash_next did not: on reaching the end of the first bucket, it ended the scan, so every matching tuple in the second bucket was overlooked.
To fix, teach _hash_next to make the same transition, using helper functions shared with _hash_readnext and _hash_readprev. _hash_next only missed the transition when the last page that it read in the first bucket had a match (otherwise _hash_readpage's loop made the required transition). Getting wrong answers also needed a matching tuple to be inserted into the bucket being populated _after_ the split began. Forward scans then lost the older tuples in the bucket being split. An incomplete split would keep the buckets in this state until an inserter finished the split at some indeterminate later time. Note that wrong answers didn't require an incomplete split. Although this fix treats the bug as the omission of a required step in _hash_next, the real problem is the way that page stepping works in general. The logic for stepping to the next page appears both in high-level routines like _hash_next and in low-level routines like _hash_readnext and _hash_readprev. If anything, _hash_next already knew too much about page stepping (cf. nbtree's _bt_next function). All of the logic around stepping really belongs in one routine, modeled on nbtree's _bt_steppage function, but that approach is much too invasive for a backpatched fix. Claude Code found this problem. The committed test case is a simplified version of the one that it wrote to demonstrate this bug. Oversight in commit 7c75ef57, which introduced page-at-a-time processing of hash index scans. Author: Peter Geoghegan <[email protected]> Author: Amit Kapila <[email protected]> Reviewed-by: Vignesh C <[email protected]> Discussion: https://postgr.es/m/CAH2-Wz=4CJK9ysZzbzxBGGTkgAg9ib8cJyCx=9q_d1r8tf0...@mail.gmail.com Backpatch-through: 14 Branch ------ master Details ------- https://git.postgresql.org/pg/commitdiff/173cf85a079516fdd2b09ed853702b05fbfcd15e Modified Files -------------- src/backend/access/hash/hashpage.c | 5 + src/backend/access/hash/hashsearch.c | 136 +++++++++++++++------ src/test/modules/Makefile | 4 +- src/test/modules/hash/.gitignore | 4 + src/test/modules/hash/Makefile | 28 +++++ .../hash/expected/hash_incomplete_splits.out | 114 +++++++++++++++++ src/test/modules/hash/meson.build | 16 +++ .../modules/hash/sql/hash_incomplete_splits.sql | 53 ++++++++ src/test/modules/meson.build | 1 + 9 files changed, 322 insertions(+), 39 deletions(-)
