1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00
Commit Graph

58203 Commits

Author SHA1 Message Date
Michael Paquier
050ad7edbe Release memory allocated by ndistinct_for_combination()
Building extended statistics of type "ndistinct" calls
ndistinct_for_combination() once for every combination of columns.  Each
call allocates arrays for the whole sample and never frees them, with
memory accumulating until the whole statistics object is built.  The
sample has 300 multiplied by target rows.  With large statistics targets
(default_statistics_target up to 10k), this can add up to gigabytes
worth of memory, useless once a combination is computed.

ndistinct_for_combination() is now called in a dedicated memory context,
reset after each combination is computed.  We only need the estimated
number of distinct values, so there is no need to copy anything out of
the memory context.

Similar fixes have been done in 83772cc78e and ad8a166ca8 for other
areas of the extended stats computations.

Author: Ilia Evdokimov <ilya.evdokimov@tantorlabs.com>
Discussion: https://postgr.es/m/20d6689e-f490-4ca7-a92f-e92f691ba07e@tantorlabs.com
Backpatch-through: 14
2026-10-14 10:16:23 +09:00
Tom Lane
38fe5a9366 Delay qp_callback processing till after join removal.
Commit 2ebf25e7d left query_planner's qp_callback call where
it had been historically, but that turns out to be a bad idea.
It means that the code reached via qp_callback is subject to the
must-be-able-to-restart rule created by looping back after join
removal.  We found one place that fails that requirement:
adjust_group_pathkeys_for_groupagg sets Aggref.aggpresorted flags,
and there's nothing that will reset those in case of a query_planner
restart, yet the selected set of Aggrefs can change.  There might be
other places with similar issues.

Fortunately, qp_callback's main charter is to compute/update pathkey
values, and that is not something that join removal depends on or
should depend on.  (Whether join removal is valid is surely not
dependent on what order the rel might get scanned in.)  Nothing else
within the restart loop depends on it either --- in other words,
the existing placement was a bit random to begin with.  So we can
fix this problem just by moving that call to below the restart loop.
That costs nothing, indeed it saves some cycles by not having to do
that processing more than once.  And removing an unstated requirement
from code that's not directly called by query_planner should help
forestall future bugs.

While the known bug only exists in v18 and up (older branches lack the
aggpresorted optimization), I've chosen to back-patch the code change
to v16 like 2ebf25e7d was.  This is the sort of API requirement that
we don't really want to be different across branches.

Reported-by: shihao zhong <zhong950419@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqSOAT1yop44B8jwacL_91rxK=QuoU8Of3NLMb9NgAO2NA@mail.gmail.com
Backpatch-through: 16
2026-10-13 17:53:20 -04:00
Tom Lane
c138ab8a9b Fix two errors in extraction of GIN indexquals from jsonpath queries.
extract_jsp_bool_expr applied De Morgan's laws incorrectly when
considering an AND operator underneath a NOT.  If one AND input
was implementable as a GIN indexqual while the other was not,
we derived an incomplete indexqual, leading to some rows not
being returned that should be.

extract_jsp_bool_expr also failed to check for methods being
applied to literals, so that for example '$.x == "42".double()'
was treated as '$.x == "42"' not '$.x == 42'.  The indexqual
thus selected the wrong rows, all of which would fail qual
recheck, leading to no rows being returned.

While we're here, improve the comments a trifle.

Reported-by: Chinmay Kanchi <cgkanchi@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAJqPDh9Cm=x8eYZ1Jf=_avd2WEqc=0t_f7_SO4igo-CKPi25_Q@mail.gmail.com
Discussion: https://postgr.es/m/CAJqPDh-tu5KY66KU8cvAEg3DQrZLzDZwjkLLa42zD+_Xm1WJAg@mail.gmail.com
Backpatch-through: 14
2026-10-13 16:33:35 -04:00
Peter Geoghegan
99ae176e43 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 <pg@bowt.ie>
Author: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Vignesh C <vignesh21@gmail.com>
Discussion: https://postgr.es/m/CAH2-Wz=4CJK9ysZzbzxBGGTkgAg9ib8cJyCx=9q_d1r8tf0ang@mail.gmail.com
Backpatch-through: 14
2026-10-10 10:26:18 -04:00
Peter Geoghegan
b87cc7a3ee Remove faulty nbtree page deletion assertion.
_bt_pagedel only builds a search stack when it needs one to locate the
downlink of the page that it's about to mark half-dead (and when it
doesn't already have one from an earlier sibling deletion that took
place during the same _bt_pagedel call).  _bt_pagedel won't build a
search stack for the page its caller passes whenever it happens to be
one that an earlier interrupted VACUUM left half-dead (since there is no
downlink to remove).  We nevertheless asserted that page deletion could
only build a search stack for that initial caller-passed page.

To fix, remove the assertion, which spuriously failed when a half-dead
leaf page was passed by the _bt_pagedel caller and its right sibling
page was empty/had to be considered for deletion during the same call
(necessitating building a search stack to locate the right sibling's
downlink).

Oversight in commit cd8c73a38, which refactored nbtree page deletion's
INCOMPLETE_SPLIT check.

Author: Peter Geoghegan <pg@bowt.ie>
Reported-by: Iliia Khaprov <i.khaprov@gmail.com>
Discussion: https://postgr.es/m/CAFO+O_p5So4MXwQ1VEcL9+9vGgODu11TTWcYq9RDbxnira8o2w@mail.gmail.com
Backpatch-through: 14
2026-10-08 14:21:13 -04:00
Richard Guo
b03eb54b14 Fix PlaceHolderVar placement for join alias expressions
When a join alias Var with nonempty varnullingrels expands to an
expression that cannot carry the nullingrels itself, such as the
RowExpr of a whole-row Var, add_nullingrels_if_needed() wraps it in a
PlaceHolderVar.  The choice of the PHV's phrels had several problems.

First, phrels was taken from all Vars in the expression.  If a LATERAL
subquery within the join has been pulled up, the expression can
contain lateral references to rels outside the join, so the PHV could
be evaluated above the outer join that is supposed to null it.  This
gave wrong results, or "wrong phnullingrels" errors.

Second, for a variable-free expression we fell back to the join's
relids but removed the join's own outer-join relid.  That leaves a set
spanning both sides of the outer join without the join itself, which
can make the PHV look nullable by that join and cause "wrong
phnullingrels" errors.

Third, that fallback raised "unsupported join alias expression" when
the Var is an outer reference from a subquery.  The restriction is
unnecessary: every planner caller passes root->parse as the query, so
the Var always belongs to root->parse regardless of its varlevelsup.

To fix, restrict phrels to the rels within the join, and if nothing is
left, evaluate the PHV at the join including its outer-join relid, at
any varlevelsup.  Add an assertion that the query is root->parse.

Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49q_gvoeOoF0+KZ-DpQaDb=nGFfSgrz2V_n1_64L4ZNVQ@mail.gmail.com
Backpatch-through: 16
2026-10-07 14:39:50 +09:00
Richard Guo
f73794bc12 Fix parser failure with whole-row join alias Vars
When a query has aggregates or GROUP BY, parseCheckAggregates()
flattens join alias Vars in the grouping expressions, target list and
HAVING clause so that aliased and unaliased references compare equal.
The parser has no PlannerInfo, so this relies on every join alias
expression being able to carry varnullingrels without a PHV.  That
doesn't hold for a whole-row Var of a join on the nullable side of an
outer join: it expands to a RowExpr, and pushing the nulling bits down
into its fields would turn a NULL row into ROW(NULL, ...).  Such
queries therefore failed with "unsupported join alias expression".

To fix, leave a nulled whole-row join Var unexpanded when no root is
available.  The planner expands it later and wraps it in a
PlaceHolderVar as before.  Nothing is lost for GROUP BY matching: a
nulled whole-row Var can only be equal to the same Var, never to an
expression over the join's columns.

This has been broken since the introduction of varnullingrels in v16.

Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49q_gvoeOoF0+KZ-DpQaDb=nGFfSgrz2V_n1_64L4ZNVQ@mail.gmail.com
Backpatch-through: 16
2026-10-07 14:39:41 +09:00
Tom Lane
f327e2a472 Don't attempt to upgrade bpchar indexes from versions before 14.
As of a32b8dc98 and friends, amcheck will complain about bpchar
indexes that claim to allow de-duplication.  This causes our
cross-version-upgrade tests to fail when upgrading from a version
that lacks those commits, since there are some such indexes in the
core regression tests.  Drop such indexes from the upgrade source
database.  (oidvector indexes would be problematic too, but
there aren't any user-defined indexes on oidvector in our tests.)

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAH2-Wzk-oO3HjLaByo8Vpse6Tpha1mqAW8DFShh-kS-Wo59ugA@mail.gmail.com
Backpatch-through: 14
2026-10-06 21:16:52 -04:00
Peter Geoghegan
80c32ab93f Rescind unsafe deduplication support.
bpchar equality ignores trailing spaces, so equal values in a column
with no length specifier can have different images.  Similarly,
oidvector equality intentionally pays no attention to the array lower
bound field.  We nevertheless allowed nbtree deduplication to be used
with indexes built with bpchar_ops, bpchar_pattern_ops, or
oidvector_ops.  A posting list split could therefore place a TID in an
index tuple whose key was equal to, but not bytewise identical to, the
corresponding table value.  This allowed index-only scans to return
subtly wrong results.

To fix, drop support function 4 from the affected opclasses (we can't
change catalog contents on branches 14 through 18, so we just disable
deduplication by adding hard-coding to the relevant support functions).
Deliberately leave the oidvector opclass alone on branches 14 through
18, though.  Disallowing oidvector deduplication on these branches would
make pg_amcheck report that pg_proc_proname_args_nsp_index has a corrupt
metapage, needlessly alarming users.

System catalog oidvector values always have a lower bound of 0, so the
issue can't cause harm there; a user can only hit it by indexing an
oidvector column that stores the output of a function like trim_array().
It seems very unlikely that any user would ever do that.

Users should REINDEX any B-Tree index on a bpchar column.

Author: Shihao Zhong <zhong950419@gmail.com>
Co-authored-by: Peter Geoghegan <pg@bowt.ie>
Reported-by: Ke <kehan5800@gmail.com>
Reported-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Bug: #19749
Discussion: https://postgr.es/m/19749-d46adf7c7d910b07@postgresql.org
Discussion: https://postgr.es/m/CAGRkXqQQ311Lg=62x5UdZtPuRFgpT6XpPMw4X9E3tgbTu162Mw@mail.gmail.com
Backpatch-through: 14
2026-10-06 18:21:31 -04:00
Nathan Bossart
d45816c24f Use a non-locking initial test in TAS_SPIN on AArch64.
Our testing showed that this is helpful at sufficiently high
contention levels and doesn't hurt performance on smaller machines.
The new TAS_SPIN macro for AArch64 is identical to the ones added
for PPC and x86_64 (see commits bc2a050d40 and b03d196be0).

Back-patch of commit 3d0b4b1068, which first shipped in v18.
Salvatore Dipietro reports that this change is beneficial on newer
Linux kernels, and the original commit has aged long enough to
provide some confidence that it won't cause problems.  v14 is left
alone since it lacks commit a82a5eee31 and will soon be out of
support.

Reported-by: Salvatore Dipietro <dipiets@amazon.it>
Reviewed-by: Jingtang Zhang <mrdrivingduck@gmail.com>
Reviewed-by: Andres Freund <andres@anarazel.de>
Tested-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/ZxgDEb_VpWyNZKB_%40nathan
Discussion: https://postgr.es/m/20260915114623.431827-1-dipiets%40amazon.it
Backpatch-through: 15
2026-10-06 14:32:42 -05:00
Tom Lane
39883fa022 Doc: correct overambitious precision claim for contrib/seg.
seg.sgml claims that a seg can store 7 significant digits, but this
is nonsense.  The underlying float4 data type is not (quite) that
precise, and seg_out() intentionally rounds off to at most FLT_DIG
decimal places.  With IEEE float arithmetic, FLT_DIG will be defined
as 6, or at least that's the case on all platforms I know of.

AFAICT this thinko goes clear back to the introduction of seg
(commit a3694b420), but it wasn't questioned until now.

Bug: #19744
Reported-by: Ke <kehan5800@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19744-8c700582bbb1d075@postgresql.org
Backpatch-through: 14
2026-10-06 15:07:36 -04:00
Nathan Bossart
1955fd0b48 Fix COPY FROM ... WHERE for negated operators.
COPY FROM runs its WHERE clause through eval_const_expressions(),
which among other things replaces NOT above an operator with the
operator's negator, if it has one (e.g., NOT (a > 0) becomes
a <= 0).  The node it builds for the negator has no opfuncid, and
since COPY FROM never calls fix_opfuncids() on the clause, nothing
fills it in before the executor needs it.  So

	COPY tab FROM stdin WHERE NOT (a > 0)

fails with "cache lookup failed for function 0".

To fix, call fix_opfuncids() on the clause, as the relcache does
for index predicates.

Oversight in commit 31f3817402.

Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/asPZRTci4oBvxR9A%40nathan
Backpatch-through: 14
2026-10-06 09:04:32 -05:00
Etsuro Fujita
104ac65e4b postgres_fdw: Fix typo in server version check in AcquireSampleRowsFunc.
s/95000/90500/g

Oversight in commit 8ad51b5f4.

Author: Etsuro Fujita <etsuro.fujita@gmail.com>
Reviewed-by: Chao Li <lic@highgo.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CAPmGK143-FdvSCmKc3bqfAQeGNs_aqVqF3op25TR_NTfBmL4BQ%40mail.gmail.com
Backpatch-through: 16
2026-10-06 18:30:05 +09:00
Richard Guo
7fb765945b Flatten join alias Vars before rechecking subquery pullup safety
pull_up_simple_subquery() rechecks is_simple_subquery() after pulling
up the subquery's own subqueries, but it flattened join alias Vars in
the subquery's targetlist only after that, and never in its quals.  A
join alias Var within the subquery, such as a whole-row Var of a join,
can expand to an expression containing lateral references to the outer
query once the join's inputs have been pulled up, and until it is
flattened is_simple_subquery() cannot see them.  We could thus pull up
a LATERAL subquery whose targetlist or quals reference rels outside
the lowest outer join above it.  This leads to assertion failures in
distribute_qual_to_rels() or "wrong phnullingrels" errors, and in some
cases to wrong query results, where rows that should have been
preserved by an outer join above the subquery are discarded.

To fix, flatten join alias Vars in the targetlist, and in the jointree
quals if the subquery is LATERAL, before the recheck.  If the recheck
fails, the flattened copy is discarded along with the rest of the
modified subquery, so no harm is done.

Back-patch to all supported branches, as this can lead to wrong query
results.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tatsuya Kawata <kawatatatsuya0913@gmail.com>
Discussion: https://postgr.es/m/CAMbWs48GFZ=3Bjc1ug9JRsB0Qupg+CGcb9js5vmTM6kY2OGWOg@mail.gmail.com
Backpatch-through: 14
2026-10-06 14:43:43 +09:00
Richard Guo
533915857a Don't reprocess PHV copies within outer aggregates' arguments
Since commit e28cf96e9, the copies of a query level's PlaceHolderVars
that were pushed down into its subqueries are preprocessed by that
level before its SubLinks are turned into SubPlans, so such a copy may
already contain SubPlans by the time the subquery is planned.  That
commit taught build_subplan not to process the SubLinks of a PHV that
is passed down as a SubPlan argument, but overlooked that such a copy
can also appear within the arguments of an outer-level Aggref,
GroupingFunc, or ReturningExpr.  The SubLinks in those arguments are
still processed when build_subplan collects the node, and that
processing descended into the already-preprocessed PHV and tripped the
no-SubPlan assertion in process_sublinks_mutator.

To fix, don't descend into PHVs when processing the SubLinks in such a
node's arguments.  Any PHV found there is a pushed-down copy that its
owning level has already preprocessed.

Back-patch to v16, as with commit e28cf96e9.

Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAJTYsWW8THbrnsmYnDqnUgg0PjGrqw2vNOWb8qx7eu191KPW3g@mail.gmail.com
Backpatch-through: 16
2026-10-06 10:59:59 +09:00
Tom Lane
a4c1c60db4 Doc: remove stray right brace in TRANSFORM option syntax summaries.
Author: Lele Gaifax <lele@metapensiero.it>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/87bj98oaen.fsf@metapensiero.it
Backpatch-through: 14
2026-10-05 20:40:33 -04:00
Nathan Bossart
af42a7a82f Fix pg_blocking_pids() for relation extension locks.
pg_blocking_pids() assumes that members of the same lock group
never block each other, but that hasn't been true for relation
extension locks since v13.  This commit teaches the function to
report lock group members as blockers for relation extension locks.
Since parallel workers are reported with their leader's PID, the
result may now include the blocked session's own PID.

Oversight in commit 85f6b49c2c.

Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Shihao Zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/apTpV8h%2BCYHf%2B1PJ%40bdtpg
Backpatch-through: 14
2026-10-05 14:52:18 -05:00
Tom Lane
d4fae29933 Handle operator-stack-overflow errors softly in tsquery and ltxtquery.
When we converted these types' input functions to report errors
through the soft-error mechanism, we missed that stack-overflow
errors can be triggered through bad user input.  Convert those
to be reported softly, too.

Bug: #19745
Reported-by: Ke <kehan5800@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19745-39cd7b93a505f9a9@postgresql.org
Backpatch-through: 16
2026-10-05 15:45:40 -04:00
Heikki Linnakangas
226e86cdad Don't sleep with vacuum_delay_point() while holding locks
It's a bad idea to sleep while holding locks, because you might block
another process that wants to acquire the same lock.  Furthermore,
it's not safe to call ProcessConfigFile() in a critical section or
while holding locks.  So avoid calling vacuum_delay_point() while
holding locks, and also make vacuum_delay_point() return quickly
without sleeping if it's called while interrupts cannot be processed.

To find the vacuum_delay_point() calls that were made while holding
locks, I added "Assert(INTERRUPTS_CAN_BE_PROCESSED())" in
vacuum_delay_point() and ran the regression tests.  I didn't include
that Assert in this commit, because there might be more places that do
that that are not covered by the regression tests, including
extensions.

In ginInsertCleanup(), there was already another vacuum_delay_point()
call later in the loop, while not holding any locks, so just remove
the other call that was made while holding the lock.

In hashbucketcleanup(), move the vacuum_delay_point() call up the
stack to its caller.  The call in hashbucketcleanup() was not able to
handle interrupts because it held a lock, and because there were no
vacuum_delay_point() or CHECK_FOR_INTERRUPTS() calls in the caller's
loop, the whole hash index vacuuming phase was uninterruptible by
pending shutdown or query cancel.  Now it can be interrupted between
buckets.  Unfortunately, hashbucketcleanup() has to process all the
bucket's pages in one go without pausing; fixing that would require
changing how hashbucketcleanup()'s lock chaining works.

In acquire_sample_rows(), move the vacuum_delay_point() call in the
loop to between pages, to a time where we're not holding the buffer
lock.

In master, also remove a misleading CHECK_FOR_INTERRUPTS() call from
pgstat_write_statsfile().  It was a no-op because we're always holding
a lock on the current dshash partition at that point.  A call that
does nothing is harmless, but it makes you think that the loop is
interruptible when in reality it's not.

Author: Kevin Rocker <me@kevinrocker.com>
Author: Andrey Borodin <amborodin@acm.org>
Author: Mostafa <mostafa.nabil.nafie@gmail.com>
Reported-by: Greg Burd <greg@burd.me>
Reported-by: Sergei Kornilov <sk@zsrv.org>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Neil Chen <carpenter.nail.cz@gmail.com>
Tested-by: Greg Burd <greg@burd.me>
Discussion: https://postgr.es/m/19628-c2b17d358181a1ea@postgresql.org
Discussion: https://postgr.es/m/492c6247-43d3-477b-8981-fb0c56767b38%40app.fastmail.com
Backpatch-through: 14
2026-10-05 13:12:46 +03:00
Richard Guo
aad7571d0e Fix relids of EC-derived join clauses for lateral UNION ALL members
When a LATERAL UNION ALL subquery is flattened into an appendrel, a
child EquivalenceMember's expression can contain lateral references to
other relations.  create_join_clause() builds a clause from such a
member with make_restrictinfo(), which computes clause_relids from the
expression, and so includes the relids of the lateral references along
with those of any outer joins that null them.  Commit 03107b4ed made
sure that clause_relids include the child's relids, but it only ever
added relids.

This is a problem when a lateral reference is nullable.  The child is
parameterized by its lateral_relids, which do not include the outer
joins that null the lateral references, so the clause fails the
join_clause_is_movable_into() assertion that
get_baserel_parampathinfo() applies to EC-derived clauses.

To fix, set a child clause's clause_relids from its members' em_relids
rather than from their expressions.  This matches how
adjust_appendrel_attrs() computes clause_relids for a child's other
join clauses.  The lateral references need not be included, since
every path for the child is parameterized by at least its
lateral_relids.  Also update num_base_rels to match, which commit
03107b4ed neglected to do.

Back-patch to v16, where outer-join relids were added to
clause_relids.  Before that, the relids of a lateral reference are
always part of the child's parameterization, so the problem does not
arise.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: wenhui qiu <qiuwenhuifx@gmail.com>
Discussion: https://postgr.es/m/CAMbWs4-cRxpQNyQJW=PkDagSDGQ=3Rp2t_fSAyROKsDStjKHUQ@mail.gmail.com
Backpatch-through: 16
2026-10-05 15:04:23 +09:00
Michael Paquier
8606467fc5 Skip isolation tests that terminate other backends on Windows
On Windows, a backend exiting resets its connection, and the client
discards any data not yet read, including the FATAL message of a
terminated backend.  isolationtester polls one connection at a time, so
when it waits on a different session the message can get lost, failing
the permutation and the tests that run after it.

wait_cleanup in injection_points (down to v17) and slot_creation_error
in test_decoding (down to v15) have this pattern, and have been failing
randomly in the buildfarm.  Let's skip them on Windows.

The cause of the instabilities is proving to be tricky to deal with,
pointing for example at 29992a6a50.  This will be tackled later,
perhaps with a backpatch (or perhaps with a HEAD-only solution), but it
is difficult to be sure at this stage of the work.  In theory,
a8458f508a should make a revert of 29992a6a50 (revert of a revert!)
safe on WIN32.

Note that 278cdea6b9, that has introduced the isolation test
slot_creation_error in test_decoding, has mentioned the potential output
instability.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAN4CZFOoiKa9E4Gnh_OzLk3S5Z6RFyg_oY1e_WddCVYhkpTVow@mail.gmail.com
Backpatch-through: 15
2026-10-05 11:11:30 +09:00
Richard Guo
e2a7f784cc Fix join alias expansion in lateral TABLESAMPLE clauses
preprocess_expression skips flatten_join_alias_vars for TABLESAMPLE
clauses, on the assumption that they cannot contain Vars of the
current query level.  That's not true once a LATERAL subquery
containing a sampled relation has been pulled up: the relation's
TABLESAMPLE clause then becomes a lateral reference of this level, and
if it referred to a join alias Var, that Var is left unexpanded.
extract_lateral_references then pulls the join alias Var out as a
lateral reference and fails with "no relation entry for relid N".

To fix, treat such clauses like lateral function and VALUES RTEs:
introduce EXPRKIND_TABLESAMPLE_LATERAL, used for the TABLESAMPLE
clause of a lateral relation RTE, and keep skipping the alias
expansion only for the non-lateral kind.

Back-patch to all supported branches, as this dates back to the
introduction of TABLESAMPLE.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/CAMbWs4834TwOtyyycyvja3MuOBkfpXy3dFAL0zt_vcM1KtqV-Q@mail.gmail.com
Backpatch-through: 14
2026-10-04 16:07:49 +09:00
Richard Guo
6bd71489d8 Set hasSubLinks when expanding a whole-row join alias reference
If a subquery has been flattened into its parent, the joinaliasvars
entries of a join above it can be arbitrary expressions rather than
plain Vars, so expanding a reference to such a join alias may insert a
SubLink into a lower-level subquery.  flatten_join_alias_vars_mutator
detects that and sets the subquery's hasSubLinks flag, but only in the
single-column code path; the whole-row path just asserted in a comment
that its recursive call would handle this, which is true only when the
alias entry is itself a Var referencing another join.

Hence a whole-row reference to such a join appearing in a sub-select
left that sub-select's hasSubLinks false, so preprocess_expression
skipped SS_process_sublinks for it, and the unprocessed SubLink
reached code that is not prepared for one: this produced "cannot
handle unplanned sub-select" from cost_qual_eval, an assertion failure
in preprocess_aggrefs, or "unrecognized node type" at execution,
depending on where in the sub-select the SubLink ended up.

To fix, make the same check in the whole-row expansion path.

Back-patch to all supported branches.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49PgeNFhQTZ2gSzwatF0_LXyegMPGt++jSfxUN7NZuQ5Q@mail.gmail.com
Backpatch-through: 14
2026-10-04 12:09:20 +09:00
Tom Lane
7f4e6f50de Fix lcov duplicate directory specification in non-VPATH builds.
In an in-tree build, "make coverage-html" invoked lcov with two
"-d ." options, because $(srcdir) is just ".".  With lcov 2.0
(and perhaps earlier versions?) that results in scanning every
foo.gcda file twice and producing counts twice what they should
be.  With later lcov versions (at least 2.3), it results in
"duplicate file" errors.

In VPATH builds we do need two -d options to cover both regular
and generated .c files.  But in in-tree builds it suffices to
specify "-d .", so suppress the second switch.

Author: Narek Galstyan <narek.galstyan@enterprisedb.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAHsn6_xCDQWe8_vVFhtFk27_xTdyVV+Dr0yWzaooBZ6+-VH-5w@mail.gmail.com
Backpatch-through: 14
2026-10-03 14:44:39 -04:00
Michael Paquier
cb157339c4 pg_dump: Include column statistics for index-backed constraints
dumpIndex() emits ALTER INDEX .. SET STATISTICS for per-column
statistics targets, but dumpConstraint() never did.  Targets set on the
expression columns of an exclusion constraint's index were silently
lost on dump/restore and pg_upgrade.

The same code can be used in the index and constraint dump code to
generate these ALTER INDEX commands.  The logic has been refactored so
that both share a new subroutine in charge of generating all these
custom SET STATISTICS, if any.

Oversight in e4fca461ab.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Andrew Krylosov <krylosov.andrew@gmail.com>
Discussion: https://postgr.es/m/CAN4CZFMd9riOuV5LkM+uV=uF-HYp49C8Fh22xWyMxptGLBCZ3A@mail.gmail.com
Backpatch-through: 14
2026-10-02 17:02:46 +09:00
Michael Paquier
caa19f80d4 Fix crash when describing a FETCH statement whose cursor is gone
FetchStatementTargetList() dereferenced the portal named by a
FetchStmt without checking that it still exists.  With the extended
query protocol, a client can sent a Parse "FETCH n FROM c" while cursor
"c" is open (which caches a result's TupleDesc), issue a CLOSE on cursor
"c", and then Describe the prepared statement or a portal bound to it.

Describe would re-resolve the target list through the named cursor, and
crash.  In a non-assert builds, this causes a NULL pointer dereference.
An assertion was triggered in assert builds slightly before the pointer
dereference.

This commit changes the describe of a FetchStmt to match with the
ExecuteStmt case: if the named cursor's portal is invalid, fail rather
than assume that the portal should always exist.

A test case is added to libpq_pipeline, backpatchable all the way down.

Author: Dirkjan Bussink <d.bussink@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/7DE248EB-7509-4F8A-9F37-4694A40BBAB7@gmail.com
Backpatch-through: 14
2026-10-02 10:43:31 +09:00
David Rowley
a13659ca66 Doc: mention platform-dependent behavior of bitshift operators
There have been several recent complaints that << and >> don't behave
the same way on all supported platforms.  There is a risk that <<
overflows the signed integer type, which is undefined behavior, and there
are platform-dependent behaviors from shifting by numbers of bits >= the
bitwidth of the type, and also from shifting by negative values.

Document this to warn unsuspecting users of these facts.

Author: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAApHDvr0O6ZF8NO=Rq9Q+Sz=FHT=NZ1kkNTXZDcNph-OWuk7TQ@mail.gmail.com
Backpatch-through: 14
2026-10-01 15:17:49 +13:00
Tom Lane
f1762b51c1 Update time zone data files to tzdata release 2026e.
Canada's Northwest Territories will move to permanent UTC-06 on
2026-11-01.  For now, assume their TZ abbreviation will be CST from
that time forward.  This affects only America/Inuvik as the rest of
the territory is covered by America/Edmonton, for which the
equivalent change was released in 2026c.

Manitoba (America/Winnipeg) will move to permanent UTC-05 on
2026-10-31.  For now, assume their TZ abbreviation will be EST
from that time forward.

(Upstream notes that more changes may be needed soon if smaller
jurisdictions choose to break away from what these have done,
but for now the plan is wait-and-see.)

Historical corrections for Colombia, Iran, and Ireland.

The backward-compatibility zone names EST5EDT, CST6CDT, MST7MDT, and
PST8PDT now conform better to POSIX.  For example, EST5EDT now always
uses the abbreviation "EST" for standard time (now always 5 hours
behind UTC) and "EDT" for daylight saving time, whereas it formerly
had different UT offsets before standard time was introduced and
sometimes used abbreviations like "LMT", "EWT" and "EPT", all contrary
to POSIX.  Also, though not specified by POSIX these names now use US
federal rules rather than rules of specific places like New York,
reverting to 2024a behavior.  This change affects only timestamps
before 1966-10-30 at 01:00 standard time.

Backpatch-through: 14
2026-09-30 17:28:14 -04:00
Michael Paquier
02c32116d5 Fix clobbering of proc entry's statusFlags during slot invalidation
ReplicationSlotRelease() copied MyProc->statusFlags unconditionally
when resetting PROC_IN_LOGICAL_DECODING, using its pgxactoff to decide
which area to update.

Slot invalidations can be done by the checkpointer or the startup
process, and ReplicationSlotRelease() ignored the fact that pgxactoff is
only meaningful for processes in the proc array, that auxiliary
processes never join.  pgxactoff would remain at 0 for these, meaning
that an incorrect set of status flags would be updated.

The consequences of this issue could be various, depending on the
statsFlags lost in the proc slot incorrectly overwritten.  Losing
PROC_AFFECTS_ALL_HORIZONS has been mentioned as the worse case, causing
VACUUM to remove rows a standby may needs even if standby feedback is
enabled.  Assertions failures are another possibility.

Let's skip the update of statusFlags unless PROC_IN_LOGICAL_DECODING is
set.  Nothing but StartupDecodingContext() sets it, and no auxiliary
processes call it.

Author: Vlad Lesin <vladlesin@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/889a06dd-45fc-423b-9dd2-87d5b5dc60c6@gmail.com
Backpatch-through: 14
2026-09-30 14:37:21 +09:00
David Rowley
3f23dd5412 Doc: add missing new line in DO example block
Reported-by: Oli Sennhauser <oli.sennhauser@fromdual.com>
Discussion: https://postgr.es/m/777637c4-9d31-498d-a8ef-645fb510bf5a@fromdual.com
Backpatch-through: 14
2026-09-30 02:17:58 +13:00
Daniel Gustafsson
c247d99e1b doc: Fix incorrect output in example
Reported-by: y.saburov@gmail.com
Reviewed-by: David G. Johnston <david.g.johnston@gmail.com>
Discussion: https://postgr.es/m/CAKFQuwZ5zQzv1uyoH1UD5ETb7+ArqF2zNXVU4Et+b0_E8bS2sQ@mail.gmail.com
Backpatch-through: 14
2026-09-29 10:49:15 +02:00
David Rowley
b8d50e1425 Fix incorrect calcSumX2 in numeric deserialize functions
calcSumX2 is used to inform the aggregate transition function whether it
should include the square of the transition value in the aggregate
state.  The deserialize functions for various numeric aggregates that do
use calcSumX2 weren't properly setting the property to true.  This does
not matter in core as we never perform any aggregate transitions after a
deserialize operation.

This fix is only required for external code which plumbs aggregate paths
together in such a way that could result in aggregate transitions being
performed after states have been deserialized.

Author: Maxime Schoemans <maxime.schoemans@enterprisedb.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/FEBF5C3D-CC53-455F-AA9D-4D377A2E957C@enterprisedb.com
Backpatch-through: 14
2026-09-29 15:49:52 +13:00
Amit Kapila
0fdfc856ea Update .abi-compliance-history for change in struct LogicalRepRelMapEntry.
Author: vignesh C <vignesh21@gmail.com>
Discussion: https://postgr.es/m/CADzfLwUJovFcnknCC9wjZKECX9xecgnGzC2r2TMV8h4QDD_jwQ@mail.gmail.com
Backpatch-through: 16-18
2026-09-28 08:34:54 -04:00
Amit Kapila
2389f898ee Fix tuple search during apply after concurrent index DDL.
When searching the local relation by index, the apply worker can use the
first match only if the index is the relation's replica identity or
primary key. Otherwise, every match must be compared with the search slot.

Only the index OID was saved in the relation map, so this was determined
again during the search. Concurrent DROP INDEX or REINDEX can change the
index status between these two checks, causing the tuple search to fail
and the change to be silently skipped as an update_missing conflict.

Fix this by recording the answer as idxisreplident in the relation map
entry and avoid getting it second time in FindReplTupleInLocalRel() and
RelationFindReplTupleByIndex().

Oversight in 89e46da5e5.

Author: Mikhail Nikalayeu <mihailnikalayeu@gmail.com>
Author: vignesh C <vignesh21@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
Discussion: https://postgr.es/m/CADzfLwUJovFcnknCC9wjZKECX9xecgnGzC2r2TMV8h4QDD_jwQ@mail.gmail.com
Backpatch-through: 16, where it was introduced
2026-09-28 06:52:24 -04:00
Fujii Masao
6f2f510845 Prevent stale pg_locks.waitstart values
Previously, pg_locks.waitstart could report the start time of a previous
lock wait for a new wait. For a regular backend, this could happen briefly
before the new start time was stored. On a standby, the startup process could
show the old time throughout the next wait, making it appear to have started
earlier than it did.

This happened because PGPROC->waitStart could remain set after a previous
wait in two cases. First, RemoveFromWaitQueue() did not clear it when a wait
was canceled due to a lock timeout, cancellation, or deadlock. Second, even
after a successful lock grant, ProcWakeup() could clear it before the waiter
stored its new start time.

Fix this by clearing waitStart in RemoveFromWaitQueue() when a failed wait
is removed, at the end of ProcSleep() to handle writes made after
ProcWakeup() cleared it, and in LockErrorCleanup() when an error bypasses
the ProcSleep() reset. This prevents pg_locks.waitstart from showing the
previous wait's time for a new wait.

Backpatch to all supported versions.

Author: Shihao Zhong <zhong950419@gmail.com>
Reported-by: Alex Shapalov <shapalov@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Andrew Krylosov <krylosov.andrew@gmail.com>
Discussion: https://postgr.es/m/CAPrb+Q+XN=sNusXiUeWmMo2H7Qgq3Y4uPekSSLkHcnCyf7GhXg@mail.gmail.com
Discussion: https://postgr.es/m/CAGRkXqQLxZBr-ouVrtaX2utMggi4+TiVMbgH04b_0JLgKryxbA@mail.gmail.com
Backpatch-through: 14
2026-09-28 14:22:38 +09:00
Michael Paquier
4cbac62871 Enforce pg_class.relchecks limit (32,767 or INT16_MAX)
pg_class.relchecks reports the number of CHECK constraints in a table,
and is stored within a smallint.  It was possible to define a table that
could overflow the counter when specifying more than 32k constraints
(new table or adding a constraint).  This would cause the table to
become undroppable, as this counter should never be negative when
dropping these constraints.

Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Jian He <jian.universality@gmail.com>
Reviewed-by: Sivaprasad <sivaprasad.postgres@gmail.com>
Discussion: https://postgr.es/m/CAEze2WjSW4qaHYnvkTtbknp85eGEirGJTLMZatotdJJKiA+_hA@mail.gmail.com
Backpatch-through: 14
2026-09-28 06:55:10 +09:00
Tom Lane
c5fcb19d04 Don't emit garbage "\[un]restrict (null)" commands in pg_dump.
_reconnectToDB() failed to consider the possibility that it could
be called without any restrict_key set.  This is reachable while
generating the "restore.sql" file in tar dump mode, which nobody
noticed because that file is mostly unused (and nothing really
bad happens anyway unless you specified --inserts mode).  But
I wonder if there are other code paths that reach the issue.

Bug: #19718
Reported-by: Pavel Kopylov <pkopylov@cloudlinux.com>
Author: Pavel Kopylov <pkopylov@cloudlinux.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19718-7e945d0ff9b5a589@postgresql.org
Backpatch-through: 14
2026-09-26 12:56:05 -04:00
Tom Lane
dcc37b7099 Doc: clarify there's no log_line_prefix in csvlog or jsonlog output.
The documentation didn't make clear that "log_line_prefix" is
not output when "log_destination" is "csvlog" or "jsonlog".

Reported-by: Michael Schönitzer <michael@schoenitzer.de>
Author: Laurenz Albe <laurenz.albe@cybertec.at>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/179032875673.1026201.6950455317699774504@wrigleys.postgresql.org
Backpatch-through: 14
2026-09-25 18:36:39 -04:00
Tom Lane
901952844b Modernize crypt-des.c a bit, avoiding dubious casts.
The header comment for this file says it assumes that "the CPU is not
picky about alignment", which we wouldn't really accept for Postgres.
The two functions that have alignment requirements have been hacked in
ways that are inconsistent and yet both ugly.  des_setkey just casts
its "const char *" argument to "const uint32 *", relying on the caller
to ensure that that pointer is actually word-aligned, which the caller
does by declaring the buffer as uint32[] and then casting to "char *".
Meanwhile des_cipher carefully memcpy's to and from an internal
uint32[] buffer, which is pretty silly given that what it's passed
must be word-aligned for the benefit of des_setkey.  And on top of
that we have a bunch of ugly casting and oddly-written pointer
arithmetic in the caller px_crypt_des.  The odd pointer arithmetic
causes warnings about possible buffer overrun when using recent gcc
at -O3 or higher.

Let's clean this up by converting the buffer variable into a union
of a uint8 array and a uint32 array, so that we can remove all these
casts, and also replace the strange loop logic with a simple subscript
variable to satisfy gcc.

Reported-by: Andres Freund <andres@anarazel.de>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Co-authored-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/2005885.1790359097@sss.pgh.pa.us
Discussion: https://postgr.es/m/3nuudxv365kjnmwjhnygdakhxuktpdjvf26rt26eb44esgqdrj@y2x3vomkrfoo
Backpatch-through: 14
2026-09-25 15:34:38 -04:00
Tom Lane
e01db37768 Silence another "may be used uninitialized" compiler warning.
gcc 12.5.0 complains about this instance in LookupFuncWithArgs().
This is the same type of problem fixed in commit f04781df5, and
it's just as obscure why this compiler version picks on this case
when others don't.  Still, silence it in the same way as f04781df5.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/1812498.1790279465@sss.pgh.pa.us
Backpatch-through: 14
2026-09-24 17:57:29 -04:00
Álvaro Herrera
a33ffaf7b8 Wait for transactions of an initial decoding snapshot to commit
SnapBuildInitialSnapshot() converts the snapshot builder's list of
committed transactions into a regular MVCC snapshot, which is then used
with HeapTupleSatisfiesMVCC().  However, a snapshot produced that way
and used as an MVCC snapshot can potentially cause data corruption, if
it captures a transaction after it writes its commit WAL record but
before it has updated its CLOG entry: it will be incorrectly used to set
hint bits as if that transaction had aborted.

Fix by having SnapBuildInitialSnapshot() wait until such transactions
have removed themselves from procarray, which guarantees correct
visibility.

Other uses of SnapBuildBuildSnapshot only use the snapshot as
historical, so they don't need the waits, but add commentary in that
function to alert possible future callers.

While at this, backpatch commit 504fe10d1d, "Fix misplaced comment in
snapbuild.c."  The comment it moved was nearby the place we modify.

This bug was diagnosed by stress-testing of REPACK (CONCURRENTLY) in
branch 19, so add a test case that tickles it using that feature in that
branch and master.  However, the bug exists in all branches, and in
branch 18 we can add a test with regular logical decoding using
injection points that tickles it.  Unfortunately that test cannot be
backpatched to earlier branches for lack of facilities.

Reported-by: Mihail Nikalayeu <mihailnikalayeu@gmail.com>
Author: Antonin Houska <ah@cybertec.at>
Author: Rui Zhao <zhaorui126@gmail.com>
Backpatch-through: 14
Discussion: https://postgr.es/m/85833.1768840165@localhost
Discussion: https://postgr.es/m/CADzfLwU78as45To9a%3D-Qkr5jEg3tMxc5rUtdKy2MTv4r_SDGng%40mail.gmail.com
2026-09-24 11:52:47 +02:00
David Rowley
6ceac2e125 Fix incorrect block accounting in TID Range Scans
heapgettup_advance_block() (or heapgettup() and heapgettup_pagemode() in
versions before v16) would incorrectly decrement rs_numblocks when
advancing to the next block.  Ordinarily this was fine, but if the TID
Range scan plan was used by a scrollable cursor and the cursor was fetched
backwards enough to result in another block being required, then
rs_numblocks may have reached 0 prematurely resulting in the scan ending
prematurely.

Reported-by: Jeff Davis <pgsql@j-davis.com>
Author: Ewan Young <kdbase.hack@gmail.com>
Author: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/6b50233fcc0f7d6f4845f083777fa9702d9612e4.camel@j-davis.com
Backpatch-through: 14
2026-09-24 01:20:53 +12:00
Daniel Gustafsson
d061147527 doc: Fix example output for format()
The example output for format() didn't show the actual output
generated for the example query.  Backpatch to all supported
branches.

Author: shihao zhong <zhong950419@gmail.com>
Reported-by: y.saburov@gmail.com
Reviewed-by: David G. Johnston <david.g.johnston@gmail.com>
Discussion: https://postgr.es/m/178979714249.1241.1230833804069549466@wrigleys.postgresql.org
Backpatch-through: 14
2026-09-23 14:07:25 +02:00
Peter Eisentraut
6b0b630b9f Silence warnings about unused global variables
Similar to commit "Remove unused global variables", silence
-Wunused-but-set-global warnings from clang 23 (included in -Wall).
These are variables that are used in assert-enabled builds only, so
annotate them with PG_USED_FOR_ASSERTS_ONLY.
2026-09-22 19:41:46 +02:00
Richard Guo
9df23331f0 Fix join removal when Vars reference the removed join via its alias
When a join has an alias, the parser marks every Var referenced
through that alias with the join's RT index as its syntactic referent
(varnosyn), even though varno points at the underlying base relation.
Since commit 2ebf25e7d, join removal strips the removed relids from
the query tree using ChangeVarNodes() with INVALID_VAR, which asserts
that the relid doesn't appear in any field identifying a single
relation.  A varnosyn that names the removed join violates that, so a
query like

    SELECT j.x FROM (t1 s(x) LEFT JOIN t2 ON s.x = t2.a) j;

with t2.a unique fails an assertion.  In non-assert builds, varnosyn
is silently set to INVALID_VAR.

Such syntactic references are still valid after the removal: the join
is only taken out of the jointree, and its RTE remains in the
rangetable through to the finished plan.  So, when deleting a relid,
leave varnosyn unchanged, as join removal did before 2ebf25e7d.

Back-patch to v16, as with commit 2ebf25e7d.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAMbWs484SQSdzWTgZYKvwtuC6J4m7acw0LfBjp3aWPvav7gC_w@mail.gmail.com
Backpatch-through: 16
2026-09-19 22:50:17 +09:00
Richard Guo
8ea97ee348 Fix preprocessing of PHV copies pushed down into subqueries
Commit e28cf96e9 preprocessed the copies of a query level's
PlaceHolderVars that were pushed down into its subqueries in a single
walk at the start of subquery_planner.  That was wrong in two ways.

First, such copies can also be inserted later, when a join alias Var
of the outer level is expanded within a LATERAL subquery or a
SubLink's subselect and the alias expression contains a PHV.  Those
copies were never preprocessed, so a SubLink within them survived into
the subquery's lateral references or into a SubPlan's argument list,
tripping an assertion in identify_current_nestloop_params or failing
in cost_qual_eval.

Second, when a pushed-down copy directly contains another PHV of the
same level, the walk preprocessed the inner one first and then the
outer one, so the outer one's preprocessing ran into the SubPlans just
created in the inner one and tripped an assertion in
flatten_join_alias_vars.

To fix, preprocess the copies right after join alias expansion
instead: within preprocess_expression, just before SubLinks are turned
into SubPlans, and for LATERAL subquery RTEs, right after their
aliases are flattened.  Preprocessing a copy handles everything within
it, including any further copies nested inside its SubLinks, so the
walker no longer looks inside a copy.

Back-patch to v16, as with commit e28cf96e9.

Reported-by: Fujii Masao <masao.fujii@gmail.com>
Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwH-acRnAk1=Ki4EiAJEt67+Rz=_jyg7pbP_c6BK4oHZ4Q@mail.gmail.com
Backpatch-through: 16
2026-09-19 21:57:46 +09:00
Masahiko Sawada
feb975917c Fix memory leak in pgoutput with streamed prepared transactions.
pgoutput records the toplevel XID in the relation's streamed_txns
list, allocated in CacheMemoryContext, when it sends a relation's
schema during a streamed transaction. We clean up that list at stream
commit and stream abort, but missed stream prepare, so the XIDs stay
around until a relcache invalidation for the relation or until the
walsender exits.

Fix by cleaning up the cache after writing the stream prepare message,
marking the schema as sent as we do at stream commit. The subscriber
applies the spooled relation messages at PREPARE time and its relation
map isn't rolled back by ROLLBACK PREPARED, so we don't need to send
the schema again even if the prepared transaction eventually aborts.

Oversight in commit 63cf61cdeb.

Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/CAJTYsWWt5aaKHCnV=jNOwABzspd-WbnhWLndDqtESDQRQ-BkKQ@mail.gmail.com
Backpatch-through: 15
2026-09-18 10:19:04 -07:00
Tom Lane
a91d664d51 Use default limitOption in subquery generated for MIN/MAX index scan.
We unintentionally copied the original query's limitOption field while
building the modified subquery.  If it was LIMIT_OPTION_WITH_TIES,
that behavior would propagate through to execution, potentially
causing a "more than one row returned by a subquery used as an
expression" error.  Fix by resetting to the default LIMIT_OPTION_COUNT.
This bug dates back to the introduction of WITH TIES.

Bug: #19694
Reported-by: Chaitanya Choudhary <chaitanyyachoudhary@gmail.com>
Author: Chaitanya Choudhary <chaitanyyachoudhary@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19694-4e61bd0475398eef@postgresql.org
Backpatch-through: 14
2026-09-18 11:02:10 -04:00
David Rowley
1d8a933369 Fix pruning of DEFAULT partition in RANGE partitioned tables
Some code added in 489247b0e tried to prune the DEFAULT partition when
the next partition had a MINVALUE clause and likewise when the final
partition to scan had a MAXVALUE clause for the final partition key in
the pruning step.  This code was incorrect as it could prune the default
partition incorrectly in cases such as:

p: PARTITION BY RANGE (a, b)
p1: FOR VALUES FROM (13, 0) TO (19, MAXVALUE)
pd: DEFAULT

SELECT * FROM t WHERE a = 32 AND b >= -7;

Here the pruning step for a = 32 and b >= -7 would see that only the
default partition needs to be scan, but it would then see that the
partition prior to the default had a MAXVALUE bound then prune away the
default thinking that it needn't be scanned.  This could result in
incorrect results.

Fix this by moving the code that looks for the MAXVALUE bound into the
code handling BTEqualStrategyNumber so that when we're pruning with a
prefix of the partition keys, we check if the bound for the offset we've
calculated lands on a partition where the next partition key is bounded
with MAXVALUE.  If so we don't include the default partition.

This leaves only the case of the first partition key.  We handle that by
modifying the existing code that was checking the last key covered by
the given values.

Author: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/CAON2xHO=sqdqp=z8zWkybnWp0AuvefnAi2ez2vOYWrhXB6hHWQ@mail.gmail.com
Backpatch-through: 14
2026-09-18 17:16:22 +12:00
David Rowley
4de221f66c Add CHECK_FOR_INTERRUPTS when building pruning steps
Building the partition pruning steps for excessively complex queries
can take some time.  Add CHECK_FOR_INTERRUPTS() to
get_steps_using_prefix_recurse() to allow more timely processing of
interruptions.

Bug: #19692
Reported-by: Qifan Liu <imchifan@163.com>
Discussion: https://postgr.es/m/19692-dacfc57cda5035fc@postgresql.org
Backpatch-through: 14
2026-09-18 15:51:46 +12:00