Re: Making Row Comparison NULL row member handling more robust during skip scans
Peter Geoghegan <pg@bowt.ie>
From: Peter Geoghegan <pg@bowt.ie>
To: Heikki Linnakangas <hlinnaka@iki.fi>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Date: 2025-07-01T18:28:24Z
Lists: pgsql-hackers
On Tue, Jul 1, 2025 at 2:03 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote: > I like how this makes row comparisons less special. To be honest I don't > quite understand what the bug was, I'd have to dig much deeper into this > to swap enough context into my memory for that. If you're interested, I can provide you with all you'll need to reproduce the infinite cycling behavior, where _bt_first is called again and again, without the scan ever making useful progress. The test data is fairly small, but it's a bit too big to just post to the list. My testing *simulates* cases where preprocessing cannot eliminate redundant keys, without actually creating an incomplete opfamily, and without really using cross-type operators in the queries. This shouldn't matter -- it's just much easier to work with. > But just reading the > comments in these patches, I get the impression that they make this all > less fragile. Technically the second patch (the row compare patch) isn't strictly necessary to make my tests stop showing infinite cycling behavior. But it's very easy to show infinite cycling behavior if I remove the "refuse to forcenonrequired on row compare" kludge that I added to _bt_set_startikey in bugfix commit 5f4d98d4 -- that's why I added it in the first place. As you said, the goal is to make row compare quals less special. And, in particular, to make it safe to remove that hack. IMO the second patch is essential, since the hack I have in place right now seems very fragile. The first patch (which adds the new preprocessing step) is unambiguously needed, to fix a live bug (without it, the infinite cycling behavior *is* still possible with redundant keys that preprocessing can't eliminate). > On bt_unmark_extra_keys() function: The function comment explains well > what it does; that's good. A few very minor stylistic remarks on its > implementation: I agree with all of your feedback; will make all those changes. > Would it be worth adding a comment that we assume keyData to be in > sk_attno order? Or is that a widely-known assumption? I don't remember. I'll add a comment like that, just to be on the safe side. There is an old comment at the top of _bt_preprocess_keys that says that scan->keyData[] is in attribute order. And I add a new one in the patch, which points out that that *isn't* always true anymore when the so->keyData[] output array has nonrequired keys. There's no comment that says what the new preprocessing function/pass expects about the order of the so->keyDatap[] (which is both its input array and its output array). > PS. Not a new thing, but the "Add coverage..." comments in the tests > seem redundant. All tests add coverage for something. I'll adjust them along those lines. Unless there are any objections, and assuming you're done giving feedback, I'll commit both patches tomorrow. Thanks! -- Peter Geoghegan
Commits
-
Make row compares robust during nbtree array scans.
- bd3f59fdb717 19 (unreleased) landed
- 4cb889d21f3d 18.0 landed
-
Make handling of redundant nbtree keys more robust.
- f09816a0a7c1 19 (unreleased) landed
- 7c365eb50429 18.0 landed
-
Revert "nbtree: Remove useless row compare arg."
- dd2ce3792754 18.0 cited
-
nbtree: Remove useless row compare arg.
- 54c6ea8c81db 18.0 cited
-
Prevent premature nbtree array advancement.
- 5f4d98d4f371 18.0 cited
-
Improvements and fixes for e0b1ee17dc
- 7e6fb5da41d8 17.0 cited
-
Fix incorrect handling of NULL index entries in indexed ROW() comparisons.
- a298a1e06fb0 9.6.0 cited
-
Fix btree stop-at-nulls logic properly.
- 882368e854b6 9.2.0 cited
-
Stop btree indexscans upon reaching nulls in either direction.
- 6980f817e83c 9.2.0 cited