Re: Let an ordering index scan hand its ORDER BY value to the target list

From: Greg Burd <greg(at)burd(dot)me>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Let an ordering index scan hand its ORDER BY value to the target list
Date: 2026-10-23 21:47:54
Message-ID: 9Rv9zoz0maEtmA-LDRIhqwBUXRIS-ZMlI5zkcvT5uWtq9STFwnLPYP1HzXE5p0k0XvnnJTsmOMTwYRlaThIV_RlULW6oaQ5-cZPG87hzboQ=@burd.me
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello,

v10 attached. It applies to master as of 126976a8ffc, and fixes an
assertion failure in 0001, a flaky test cfbot caught in 0007, and
several smaller problems.

The bug: IndexStoreOrderByValues() asserted that every ORDER BY key is
passed by value, but only the keys the target list reads have to be.
Another key can be by-reference: btree_gist's <-> on timestamps returns
an interval. So this crashed a cassert build:

CREATE INDEX ON t USING gist (p, ts); -- btree_gist
SELECT p <-> point(3,4), ts <-> '...' FROM t
ORDER BY p <-> point(3,4), ts <-> '...';

The fix stores only by-value keys and gives the others a null, since
nothing reads them. There's a btree_gist test for it now. Non-assert
builds were safe, they only kept a pointer they never used.

cfbot's 32-bit job failed on v9 in the pass that runs the regression
suite against an already running server. The Parallel Append test in
0007 used two partitions of the same size, so the order of the children
in the plan depended on how many pages VACUUM could mark all-visible
while other sessions held snapshots. The partitions now differ in
size. I reproduced the flip by holding a snapshot during VACUUM, and
checked that the new order holds and that the other parallel tests
keep their plans with nothing all-visible.

The rest:

* The series' tests in gist.sql reset enable_seqscan and
enable_bitmapscan to their defaults, which the file had turned off.
That turned the existing gist_ios_tupdesc test into a Seq Scan, so it
no longer tested what it was written for. The file's settings are
now restored before that test, and its output matches master again.

* Two tests could not fail. The box EPSILON check compared the
operator with itself. It now compares the scan's value with the
operator's, and fails when box_ops is allowed to qualify. The 0002
plan test ran with seqscan off. Now it runs with seqscan on, and it
flips to Seq Scan + Sort when the costing change is reverted. (0001,
0002)

* Tests that printed raw <-> distances now run with
extra_float_digits = 0. The join tests pin the join method, so
the plans don't depend on close hash-versus-merge costs. The test
that an index on only one partition doesn't count now runs EXPLAIN
VERBOSE, so it shows the join computing the value. (0001-0003,
0006, 0007)

* indexorderbyexact is now read_write_ignore: only setrefs.c reads it.
indexorderbytlist, which is a count and not a List, is renamed
indexorderbynused. It now counts the distinct ORDER BY values the
target list reads, so "Order By Values Used" in EXPLAIN can't exceed
the number of ORDER BY keys when the target list repeats one.
ruleutils.c checks dpns->plan for NULL before looking at it, as its
neighboring branches do. (0001)

* index_path_orderby_target() no longer adds the same value twice
when two ORDER BY keys are equal. (0003)

* add_extras_append_path() goes on to build the parallel Append when
some child has no non-partial path that emits the values. Before,
it gave up on all three Appends. (0007)

* Smaller cleanups: no Bitmapset allocations in path_target_cost()'s
outer-join test, one nestloop Material guard instead of two, a
shared query_tlist_exprs(), an Assert in join_path_target(), an
early return in indexonly_free_exprs() for indexes with no
expression columns, and some comments fixed. (0001, 0006, 0007)

0005 is unchanged. Each patch builds without warnings and passes the
regress, isolation and btree_gist suites on its own. The series passes
the running-server pass and CI on Linux (32- and 64-bit), macOS,
Windows and MinGW.

best.

-greg

Attachment Content-Type Size
v10-0005-Let-an-index-only-scan-win-on-the-index-expressi.patch text/x-patch 14.4 KB
v10-0006-Carry-index-computed-values-up-through-joins-and.patch text/x-patch 79.1 KB
v10-0002-Don-t-charge-an-ordering-index-scan-for-ORDER-BY.patch text/x-patch 23.5 KB
v10-0004-Don-t-charge-an-index-only-scan-for-index-expres.patch text/x-patch 8.4 KB
v10-0003-Let-an-ordering-index-scan-below-a-join-emit-its.patch text/x-patch 19.6 KB
v10-0007-Carry-index-computed-values-through-outer-joins-.patch text/x-patch 53.4 KB
v10-0001-Let-an-ordering-index-scan-hand-its-ORDER-BY-val.patch text/x-patch 54.2 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message surya poondla 2026-10-23 21:50:18 Re: Parallel vacuum: workers together with leader could overrun cost budget
Previous Message Greg Burd 2026-10-23 21:36:39 Re: Trying out <stdatomic.h>