postgresql.git
20 min agoFix possible index corruption in pg_trgm GiST indexes master github/master
Fujii Masao [Wed, 4 Nov 2026 02:18:49 +0000 (11:18 +0900)]
Fix possible index corruption in pg_trgm GiST indexes

Commit 911e7020770, which added configurable signature lengths,
introduced an error in how gist_trgm_ops index entries are combined.
Some entries could lose the flag identifying their format, causing
later inserts to treat them as empty and lose information about
existing entries.  As a result, queries using these indexes could
miss matching rows.

Fix this by preserving the format flag when combining index entries,
so that subsequent inserts correctly retain the information they
represent.

This fix does not repair existing indexes.  Users should REINDEX all
existing gist_trgm_ops indexes after upgrading to a release containing
this fix.

Backpatch to all supported versions.

Author: Nate Clark <natec425@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/19720-b3e83f5e99c485c5@postgresql.org
Backpatch-through: 14

22 min agoFix memory leaks when freeing WAL readers
Fujii Masao [Wed, 4 Nov 2026 02:16:44 +0000 (11:16 +0900)]
Fix memory leaks when freeing WAL readers

Commit 3f1ce97346 introduced a circular buffer for decoded WAL records,
with separate allocations for records that do not fit in the buffer.
However, XLogReaderFree() did not release separately allocated
records remaining in the decode queue. In particular, the last record
returned by XLogReadRecord() remains queued until released, so freeing
the reader could leak that record.

For many callers, the leaked memory is reclaimed when the containing
memory context is reset or deleted. However, it can accumulate in
long-lived contexts. For example, when checkpointing prepared
transactions, XlogReadTwoPhaseData() creates a WAL reader, reads the
PREPARE record, and frees the reader. Large PREPARE records can
therefore leave allocations in checkpointer_context, which is not
reset during normal operation. These allocations accumulate until
an error resets the context or the checkpointer exits.

Fix this by calling ResetDecoder() in XLogReaderFree() to release all
separately allocated records in the queue. Do this before freeing the
decode buffer, since the queue can also contain records stored in that
buffer.

Backpatch to v15, where the circular WAL decoding buffer was
introduced.

Author: Tomás Senart <ts@perfloop.ai>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAEEBa3Uai8TGPd6P5SX_fzbu3KHMwSvu9WuqA8JPSPQ1RJR8fQ@mail.gmail.com
Backpatch-through: 15

42 min agoFix handling of nested values in "exprs" for pg_restore_extended_stats()
Michael Paquier [Wed, 4 Nov 2026 01:55:58 +0000 (10:55 +0900)]
Fix handling of nested values in "exprs" for pg_restore_extended_stats()

check_all_expr_argnames_valid() iterated over the keys of each
expression object without skipping nested containers, so an unknown key
whose value is an array or an object broke the expected key/value token
sequence.  This caused an assertion failure, or an infinite loop that
cannot be canceled in non-assert builds.

This issue is fixed by skipping any nested containers, as we expect a
single array with a single sets of key/value pairs.

While on it, remove an unused allocation of the invalid key name.
This one has been noticed in passing.

Author: Ilia Evdokimov <ilya.evdokimov@tantorlabs.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/f0034efa-66fb-4963-9872-c089dd021007@tantorlabs.com
Backpatch-through: 19

115 min agoFix Memoize to correctly use clause's input collation
David Rowley [Wed, 4 Nov 2026 00:43:17 +0000 (13:43 +1300)]
Fix Memoize to correctly use clause's input collation

When building Memoize cache keys from a parameterized path's join clauses,
paraminfo_get_equal_hashops() used the outer side expression of each
clause verbatim, which meant the cache was hashed and probed using that
expression's collation rather than the input collation of the join
condition.

If the expression's collation is nondeterministic and the clause compares
using a different collation, values that the clause can distinguish, such
as 'abc' and 'ABC' under a case-insensitive collation, could be treated as
equal by the cache.  This could cause a lookup to return the cached
results for another value, giving wrong query results.

Here we fix this by relabeling the cache key expression with the join
clause's input collation, so that cache lookups match values the same way
as the join clause does.

Author: shihao zhong <zhong950419@gmail.com>
Reviewed-by: Manu <manuelreyesbravo@gmail.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqTBsBegZ8rNMYjwkeu1V5wRQ06zR6jTVickqP_3E7mb8g@mail.gmail.com
Backpatch-through: 14

3 hours agoImprove stability of authentication test 007_pre_auth
Michael Paquier [Tue, 3 Nov 2026 23:38:32 +0000 (08:38 +0900)]
Improve stability of authentication test 007_pre_auth

The injection point wait used by the test could be reached by autovacuum
workers or the logical replication launcher, leading to sporadic
failures.

The configuration of the test is tweaked so as these kinds of processes
are not spawned anymore, which should be enough to silence the problems.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/c984ed89-cac1-47a9-91fa-4d3287722203@gmail.com
Backpatch-through: 18

3 hours agotest_custom_stats: Add test for drop of variable-sized stats kind
Michael Paquier [Tue, 3 Nov 2026 23:05:17 +0000 (08:05 +0900)]
test_custom_stats: Add test for drop of variable-sized stats kind

pgstat_drop_matching_entries() with a non-NULL callback while scanning
all the variable-numbered stats kinds had no test coverage.  d52c24b0f80
had an equivalent in the test module injection_points, that had no
coverage since the tests for custom stats kinds have been moved to
test_custom_stats.

This commit adds an equivalent coverage here by dropping all the custom
variable-sized stats entries through pgstat_drop_matching_entries().  An
extra test checking that other variable-sized stats kinds are untouched
is included.

This is a hole in the tests of v19, but it's not critical in any way so
no backpatch is done.

Author: Sami Imseih <samimseih.pg@gmail.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/aufa5srSxC4pu5OF@paquier.xyz

11 hours agopg_plan_advice: Handle custom scans that replace a join
Robert Haas [Tue, 3 Nov 2026 15:11:04 +0000 (10:11 -0500)]
pg_plan_advice: Handle custom scans that replace a join

pgpa_relids() ignored CustomScan nodes, so a custom scan that replaced
a join caused the plan walker failed with "plan node has no RTIs". Fix
by returning custom_relids, so that the node is then treated as an
ordinary scan of several relations.  This allows JOIN_ORDER advice to
handle it correctly.

Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/20260827171830.68.noahmisch@microsoft.com
Discussion: https://postgr.es/m/sSMpyoJ12CV5Y3uS-T_8Z3M1xsJBELBd-Vh5DmlC9_jy9TOqMuWzr8-TuXrBpL8AlPlyEFkyQ4wX5guJCyVizY-R2UET0DpIEeA1aSsUjk4=@pm.me
Author: Dongpo Liu <poe.liu@pm.me>

13 hours agoRemove git-external-diff from tools directory
Daniel Gustafsson [Tue, 3 Nov 2026 13:13:36 +0000 (14:13 +0100)]
Remove git-external-diff from tools directory

The git-external-diff bash script could not be executed due to syntax
errors without it being reported, which indicates that it hasn't been
used by anyone in a long time.  Rather than spending energy on fixing
dead code, the conclusion in the thread was to remove it.

Reported-by: zmuxuny <xiahoumuxuan@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAMPOERnKK-vNtc_Ooddb9WGbDepGi1=pxOFfiGrb4_Cqzyu69w@mail.gmail.com

16 hours agoClean up code comments for pg_wchar_tbl
Peter Eisentraut [Tue, 3 Nov 2026 06:58:15 +0000 (07:58 +0100)]
Clean up code comments for pg_wchar_tbl

The documentation for the functions in the fields of pg_wchar_tbl was
spread out all over the place and was missing a lot of detail.  Move
and expand this at the definition of the struct.  (See also struct
TableAmRoutine in access/tableam.h for inspiration.)

Also remove unnecessary typedefs, except where they were used
elsewhere as well.  This indirection makes the code documentation
harder to follow.  And some of those typedefs had nonsensical names,
like *_converter for functions that didn't do any converting.

Reviewed-by: Greg Burd <greg@burd.me>
Discussion: https://www.postgresql.org/message-id/flat/637d73f4-e088-4ead-b9e6-1ddb4cd4693f%40eisentraut.org

20 hours agodoc: Match built-in function parameter names to their SQL names
Fujii Masao [Tue, 3 Nov 2026 06:01:02 +0000 (15:01 +0900)]
doc: Match built-in function parameter names to their SQL names

Several documented function signatures used parameter names that
differed from the registered SQL names, causing named-argument calls
using the documented names to fail. Update the signatures and
corresponding descriptions to use the SQL-visible names, without
affecting existing calls.

Backpatch to all supported versions, except for the changes to
pg_logical_emit_message and pg_input_error_info, which are
backpatched through v17 and v16, respectively.

Reported-by: Mi cro <micro6947@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/19D9D4CB-8C31-493E-982A-1E17042D68C5%40gmail.com
Backpatch-through: 14

20 hours agodoc: Fix column name in routine_sequence_usage documentation
Fujii Masao [Tue, 3 Nov 2026 05:58:56 +0000 (14:58 +0900)]
doc: Fix column name in routine_sequence_usage documentation

The sequence catalog column of information_schema.routine_sequence_usage
is named sequence_catalog in the view definition, but the documentation
previously called it schema_catalog.  Correct the documented column name
to match the view.

Backpatch to all supported versions.

Reported-by: Mi cro <micro6947@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/179342977864.1246.4971529844925475150@wrigleys.postgresql.org
Backpatch-through: 14

20 hours agodoc: Correct setting restrictions for vacuum_max_eager_freeze_failure_rate
Fujii Masao [Tue, 3 Nov 2026 05:54:02 +0000 (14:54 +0900)]
doc: Correct setting restrictions for vacuum_max_eager_freeze_failure_rate

The documentation incorrectly stated that this parameter could only
be set in postgresql.conf or on the server command line. However, it
is a PGC_USERSET parameter and can therefore be changed by any user
within a session.

Remove the incorrect restriction while retaining the note about the
per-table storage parameter override.

Backpatch to v18, where this parameter was introduced.

Author: Afrah Razzak <mypg.afrah@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAAJ6gzGeup6WPpraF1g6iWYOQsvLmhKk94acJ=-iq+Gg_x9W0w@mail.gmail.com
Backpatch-through: 18

22 hours agoReject incremental backups based on a backup from a divergent history
Fujii Masao [Tue, 3 Nov 2026 04:03:38 +0000 (13:03 +0900)]
Reject incremental backups based on a backup from a divergent history

After a failover, an incremental backup could accept a prior backup
whose WAL range extends beyond the point where the new primary left the
old timeline. Combining these backups could retain pages from the
abandoned history, producing a corrupt backup that might still recover
and start successfully.

The validation checked the end of the prior backup's final WAL range
against the new backup's start LSN, but not against the timeline's
switch point. This allowed an incompatible prior backup to pass
validation once the new primary had advanced far enough.

Reject incremental backups if the prior backup's final WAL range
extends beyond the timeline's switch point.

Backpatch to v17, where incremental backup was introduced.

Author: Sai Pranav <rajasaipranav0@gmail.com>
Co-authored-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAPHduZC9pWm_vjznmhZNFsDZKLimqc6dKXOozLUKZVPs19zbZg@mail.gmail.com
Backpatch-through: 17

24 hours agopg_waldump: Align WAL read error locations with other tools
Fujii Masao [Tue, 3 Nov 2026 01:52:45 +0000 (10:52 +0900)]
pg_waldump: Align WAL read error locations with other tools

When reading WAL fails, pg_rewind and pg_walinspect report the
position where the failed read began, followed by the detailed error
message. In contrast, pg_waldump's "error in WAL record at ..."
prefix reported the position of the last successfully read record.
This was misleading because the prefix pointed to a successfully
read record rather than the start of the failed read.

Make pg_waldump report the position where the failed read began,
consistent with pg_rewind and pg_walinspect.

Note that this position usually identifies the start of the next
record, but may precede it when a page header must be skipped.
It may also differ from the actual error location when reading
a record that spans multiple pages. Nevertheless, it is consistent
with the other tools and less misleading than reporting the last
successfully read record.

Author: Rahul Yadav <rahul@rhyadav.dev>
Reviewed-by: Surya Poondla <suryapoondla4@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/P2qIkq4--F-9@rhyadav.dev

24 hours agoFix incorrect LSNs in WAL decoding error messages
Fujii Masao [Tue, 3 Nov 2026 01:49:40 +0000 (10:49 +0900)]
Fix incorrect LSNs in WAL decoding error messages

Commit 3f1ce97346 introduced a circular WAL decoding buffer,
allowing records to be decoded before they are consumed. However,
decoding error messages continued to report the location of the last
record consumed instead of the record that failed decoding. With
recovery prefetching, the reported location could be many records
behind the failing record, making WAL problems harder to diagnose.

Fix this by reporting the location of the record being decoded.
Errors now identify the failing record even with recovery prefetching,
making it easier to investigate malformed WAL during recovery or with
tools such as pg_waldump and pg_walinspect.

Backpatch to v15, where the WAL decoding buffer was introduced.

Author: Rahul Yadav <rahul@rhyadav.dev>
Reviewed-by: Surya Poondla <suryapoondla4@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/P2qIkq4--F-9@rhyadav.dev
Backpatch-through: 15

24 hours agoFix lost wakeups in physical WAL senders
Fujii Masao [Tue, 3 Nov 2026 01:46:41 +0000 (10:46 +0900)]
Fix lost wakeups in physical WAL senders

Physical WAL senders could sleep even when flushed WAL was waiting to
be sent, delaying replication and synchronous commits until another
event woke them. In the reported case, commits stalled for about ten
seconds, until the standby sent its next periodic status report.

Commit bc971f4025c changed WAL sender wakeups to use condition
variables, which notify only senders already on the waitlist.
However, XLogSendPhysical() checks the flush position before
WalSndWait() joins the waitlist. If WAL is flushed between these two
steps, the wakeup can be missed, leaving the sender asleep despite
having more WAL to send.

Fix this by rechecking the flush position after joining the waitlist
and returning to the send loop if more WAL is available. For cascading
senders, also check for promotion or a timeline change, which require
the sender to revisit the current timeline even if the flush position
has not advanced.

Backpatch to v16, where commit bc971f4025c introduced the
condition-variable wakeup mechanism.

Author: Alex Speller <alex@alexspeller.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/mvx5bs7q.33b99c32-67d8-4373-8611-7a8250fb2fd3@we.are.superhuman.com
Backpatch-through: 16

25 hours agoMake Memoize cache keys only of Params from outer query levels
Richard Guo [Tue, 3 Nov 2026 00:45:51 +0000 (09:45 +0900)]
Make Memoize cache keys only of Params from outer query levels

Commit 708eb5158 made each PARAM_EXEC Param buried inside a larger
Memoize cache key expression a cache key by itself, and, in master
only, commit f8da64e6d extended that to the Params in the memoized
relation's base quals, targetlist and join clauses.  Both meant to
catch Params supplied by an outer query level, but they took every
PARAM_EXEC Param they found, including the output Params of initPlans
and SubPlans.

When an initPlan's output Param is made a cache key, it is evaluated
on every cache probe, which runs the initPlan even where the query
doesn't need it, such as in a CASE arm that is never taken, and can
raise an error the query shouldn't raise.  A SubPlan's output Params
have a value only while the SubPlan evaluates its testexpr, so making
a cache key of one fails with "plan should not reference subplan's
variable".

To fix, make cache keys only of the Params listed in some outer query
level's plan_params, as those hold values supplied by outer levels and
are always safe to evaluate.  Any other Param is left to purge the
cache when it changes.

Back-patch to all supported branches.

Reported-by: Fujii Masao <masao.fujii@gmail.com>
Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwHdaau1KooFbY10=MDhKtFVgpmPrDiwNpEe6bWu7wpQYA@mail.gmail.com
Backpatch-through: 14

26 hours agoDelay checkpoint start while creating a multixact
Heikki Linnakangas [Mon, 2 Nov 2026 23:39:20 +0000 (01:39 +0200)]
Delay checkpoint start while creating a multixact

A checkpoint starting between the CREATE_ID record and the SLRU update
could lose the multixact after a crash.

Author: shihao zhong <zhong950419@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAGRkXqSuiJ_X4+Z6rsD42pcuACnD9PhoQ-Os+mUJNmJarBWkNg@mail.gmail.com
Backpatch-through: 14

27 hours agoAdd REPACK progress phases for logical decoding setup.
Masahiko Sawada [Mon, 2 Nov 2026 23:00:30 +0000 (15:00 -0800)]
Add REPACK progress phases for logical decoding setup.

Previously, REPACK (CONCURRENTLY) reported everything it did before the
heap scan as "initializing", including enabling logical decoding and
setting up the logical decoding context. Setting up the context waits
for the transactions that have a transaction ID assigned to end and
therefore can take arbitrarily long, but users couldn't tell that wait
apart from the rest of the setup.

Add two phases, "enabling logical decoding" and "initializing logical
decoding". As these steps run in the decoding worker, the worker tells
the backend running REPACK which phase to report through shared
memory, and the backend reports it while waiting for the worker.

Bump catalog version.

Author: Sami Imseih <samimseih.pg@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Manu <manuelreyesbravo@gmail.com>
Discussion: https://postgr.es/m/CAN12%2BYJOeOyPYB5JS28VE_%2Brzg%3DRbzQXfj58TGfMYwv-TX9mJA%40mail.gmail.com

28 hours agoFix BRIN minmax-multi distance calculation for OID
Tomas Vondra [Mon, 2 Nov 2026 22:11:38 +0000 (23:11 +0100)]
Fix BRIN minmax-multi distance calculation for OID

The oid_minmax_multi_ops opclass simply calculated the distance using
brin_minmax_multi_distance_int4. That however interprets the values as
int32, so OIDs above PG_INT32_MAX were treated as negative values, and
ranges crossing the boundary ended with a negative distance.

With assert-enabled guild, this tripped the (a1 <= a2) check. Without
asserts, the index was less efficient.

Fix by introducing brin_minmax_multi_distance_oid, correctly treating
the OID values as unsigned.

This required a catalog change (and catversion bump), so it can't be
backpatched. It'd be possible to adjust brin_minmax_multi_distance_int4
to handle the (a1 > a2) case differently. But that'd lose the assert,
and it does not seem worth it (indexes on OIDs don't seem very common).

Author: Tomas Vondra <tomas@vondra.me>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/CALdSSPgBvXz-VSF0p-5k%3D_uFfN38cWrERmm_AC4K67N6MWQhmg%40mail.gmail.com

29 hours agoMake parallel vacuum processes share the cost limit.
Masahiko Sawada [Mon, 2 Nov 2026 21:21:38 +0000 (13:21 -0800)]
Make parallel vacuum processes share the cost limit.

Since commit 40d964ec99 introduced parallel vacuum in v13, each
process taking part in it has slept for every vacuum_cost_limit cost
units it incurred on its own, so the leader and its workers together
could consume the budget several times over.

Fix by scaling each process's delay by the number of processes active
in the parallel vacuum. The cap on a single delay is scaled the same
way but also limited to one second, as sleeping longer in pg_usleep()
keeps the process from responding to latches and signals promptly.

While the new behavior is the correct one, backpatching it to v18 and
older would make parallel VACUUM with cost-based delay slower after a
minor update, and users would need to retune the parameters. Since we
haven't received any complaints about the old behavior, we don't
backpatch it to those branches for now. On v19, however, parallel
autovacuum breaks autovacuum_vacuum_cost_limit, whose value is divided
among autovacuum workers so that their sum doesn't exceed it, because
parallel workers aren't counted. So backpatch to v19.

Author: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: surya poondla <suryapoondla4@gmail.com>
Tested-by: Manu <manuelreyesbravo@gmail.com>
Discussion: https://postgr.es/m/CALj2ACWDhGH_ACJYHvxHVbL9GZ8AgMoJFnf-u5=bWx7NZtYBRQ@mail.gmail.com
Backpatch-through: 19

29 hours agoFix BRIN minmax-multi distance for tid values
Tomas Vondra [Mon, 2 Nov 2026 20:49:28 +0000 (21:49 +0100)]
Fix BRIN minmax-multi distance for tid values

The distance function for tid values maps item pointers to float8 as

  (block * MaxHeapTuplesPerPage + offset)

but the multiplication was done in uint32 arithmetic, so for high block
values (above 14759338, ~112GB) the result wrapped around. The distance
would then be very inaccurate (possibly negative), resulting in a less
efficient index.

Fix by doing the arithmetics in double.

It's also possible the (user-supplied) item pointers have offsets
greater than MaxHeapTuplesPerPage, confusing the mapping to double
value. This commit does not try to address that, it's not clear what
would be a better mapping.

Author: Tomas Vondra <tomas@vondra.me>
Backpatch-through: 14
Discussion: https://postgr.es/m/CALdSSPgBvXz-VSF0p-5k%3D_uFfN38cWrERmm_AC4K67N6MWQhmg%40mail.gmail.com

29 hours agoHandle numeric overflow in numeric_minmax_multi_ops
Tomas Vondra [Mon, 2 Nov 2026 19:09:59 +0000 (20:09 +0100)]
Handle numeric overflow in numeric_minmax_multi_ops

When calculating the distance between numeric values, the code could
overflow in two ways. A subtraction of two finite values may still
overflow, or the result may not fit into float8.

The distances don't need to be perfectly accurate, although it may make
the index less efficient. And for most minmax-multi opclasses it works
like that, but for numeric the functions may error-out. That prevents
summarization, either when creating an index or later during vacuum.

Fix by using numeric_sub_safe() and numeric_float8_no_overflow(), and
returning infinity when either of those fails. The older releases need
to use numeric_sub_opt_error(), but the principle is the same.

Also, handle NaN values the same as for float4/float8. When both values
are NaN, return distance 0. When one value is NaN, return infinity.

While at it, free the detoasted copies of arguments, and the calculated
numeric distance. For small values it does not matter, but for extreme
numeric values it may make a difference.

Reported by Kirill Reshke, with a patch fixing the issue. Various
improvements and backpatching by me.

Backpatch to 14, where minmax-multi indexes were introduced.

Author: Kirill Reshke <reshkekirill@gmail.com>
Author: Tomas Vondra <tomas@vondra.me>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Backpatch-through: 14
Discussion: https://postgr.es/m/CALdSSPgBvXz-VSF0p-5k%3D_uFfN38cWrERmm_AC4K67N6MWQhmg%40mail.gmail.com

33 hours agoRemove unused parameters from self-join elimination functions
Fujii Masao [Mon, 2 Nov 2026 16:57:47 +0000 (01:57 +0900)]
Remove unused parameters from self-join elimination functions

Remove root, from, and to from split_selfjoin_quals(), and root
from match_unique_clauses(). These parameters have been unused
since self-join elimination was committed.

Author: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Miłosz Bieniek <bieniek.milosz@proton.me>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAHewXNmwCFH5bk0ANX8wRG8Y_4c9jh8OTKceNM1W6ijDS3DzLA@mail.gmail.com

33 hours agodoc: Clarify the description of postmaster.pid fields
Fujii Masao [Mon, 2 Nov 2026 16:57:13 +0000 (01:57 +0900)]
doc: Clarify the description of postpid fields

Document the postmaster status and note that the shared memory field
is empty on Windows. Also mention the shared memory segment ID in
the pidfile.h comment.

This is a follow-up of commit fa5ecff759b.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at>
Discussion: https://postgr.es/m/CAHGQGwGQRpEyTdoHJr86x=JmF4413E87MK3Jai09UvSvuotqVg@mail.gmail.com

34 hours agoFix missing tts_tid assignments in ExecForceStoreHeapTuple().
Nathan Bossart [Mon, 2 Nov 2026 16:13:52 +0000 (10:13 -0600)]
Fix missing tts_tid assignments in ExecForceStoreHeapTuple().

ExecForceStoreHeapTuple() clears the slot before storing the tuple,
which invalidates the slot's TID, but it only sets the TID again
for slots of type TTSOpsHeapTuple.  Besides producing wrong query
results, this can lead to data corruption if an affected tuple is
locked (e.g., via SELECT ... FOR UPDATE).  To fix, set the slot's
TID for the other kinds of slots, too.

Oversight in commit b8d71745ea.

Author: Virender Singla <virender.cse@gmail.com>
Co-authored-by: Greg Burd <greg@burd.me>
Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Nikolay Samokhvalov <nik@postgres.ai>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Tested-by: Shihao Zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/CAM6Zo8wZOLnCWRO_tuuXVX9J4N4JN6GsEnk8WJtT0%3D_0zy-1dw%40mail.gmail.com
Discussion: https://postgr.es/m/0498c10f-839b-4f68-9994-c29b454e55a4%40app.fastmail.com
Backpatch-through: 14

39 hours agoAdd more pg_attribute_counted_by() to various flexible array members
Peter Eisentraut [Mon, 2 Nov 2026 10:02:39 +0000 (11:02 +0100)]
Add more pg_attribute_counted_by() to various flexible array members

Annotate flexible array members whose element count is held by another
member of the same struct, so that the compiler knows the real extent
of these arrays.

This continues the work from commit 7a04cac0c3b.  In one case, the
order of assignments to the counted and counting fields had to be
adjusted.

Extension code could in theory be affected by the new annotations in
the header files, but it is mostly unlikely that extensions would
build or resize these structs themselves, and in any case a violation
would show up as a new warning or sanitizer failure, not silent
breakage.

Author: Tristan Partin <tristan@partin.io>
Reviewed-by: Japin Li <japinli@hotmail.com>
Reviewed-by: Greg Burd <greg@burd.me>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://www.postgresql.org/message-id/flat/DKBEBF32QLUA.3L2DJRPUYNKHZ%40partin.io

44 hours agoDelay checkpoint start in RecordTransactionAbortPrepared()
Michael Paquier [Mon, 2 Nov 2026 06:17:57 +0000 (15:17 +0900)]
Delay checkpoint start in RecordTransactionAbortPrepared()

ROLLBACK PREPARED flushes its abort record and then updates pg_xact.
Nothing prevented a checkpoint from setting its redo pointer between
these two steps.  A crash before the removal of the 2PC state file would
then cause recovery to begin after the abort record and would restore
the transaction as prepared, even though its rollback has been
aknowledged.  Standbys could for example replay the abort record, and a
follow-up COMMIT PREPARED on a primary could make them flip a
transaction from aborted to committed.

Losing an abort is harmless for a regular transaction, but not for a
prepared transaction whose 2PC state file is still on disk.  This issue
is fixed by setting DELAY_CHKPT_START (delayChkpt in v14) around the
abort record and the pg_xact update, as done for COMMIT PREPARED.

This issue exists since the introduction of 2PC, since d0a89683a3a4.

Author: Shihao Zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqRhpq=fd8Qf_-Ki1OW7b1iL+o3YuHiHQhLw5RUJy2JGXQ@mail.gmail.com
Backpatch-through: 14

45 hours agoFix reuse of stale hash tables by duplicated hashed SubPlans
Richard Guo [Mon, 2 Nov 2026 05:36:38 +0000 (14:36 +0900)]
Fix reuse of stale hash tables by duplicated hashed SubPlans

The same SubPlan can appear more than once in a plan tree.  For
example, when an equivalence class has a constant member containing a
SubPlan, each derived "member = constant" clause references that
SubPlan; a hash join's hash keys and its hash clauses can both contain
it; and extract_restriction_or_clauses() can copy it into a new
restriction clause while leaving it in the original join clause.  Each
reference gets its own SubPlanState, with its own hash tables, but
they all share the subplan's PlanState.

A hashed SubPlan whose subquery references outer query levels must
rebuild its hash tables whenever those parameters change.
ExecHashSubPlan() detected that by checking chgParam of the subplan's
PlanState.  But buildSubPlanHash() rescans that PlanState, which
clears its chgParam, so after one SubPlanState had rebuilt its hash
tables, the others no longer saw the change and kept probing hash
tables built for previous parameter values, producing wrong query
results.

To fix, give each SubPlanState its own flag to mark its hash tables as
stale.  ExecReScan() sets it, alongside propagating chgParam to the
node's subplans, ExecHashSubPlan() checks it instead of the subplan's
chgParam, and buildSubPlanHash() clears it.  The new field fits into
existing padding in SubPlanState, so this does not change the struct's
size or the offsets of its other fields.

Reported-by: Samuel Olaoye <dapsalmy@gmail.com>
Author: Rahul Yadav <rahul@rhyadav.dev>
Reviewed-by: Alexandra Wang <alexandra.wang.oss@gmail.com>
Reviewed-by: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/179087936257.78721.1170374394656748858@mail.gmail.com
Backpatch-through: 14

2 days agoFix double-free when XMLSERIALIZE(... INDENT) output exceeds 1GB.
Tom Lane [Mon, 2 Nov 2026 01:45:35 +0000 (20:45 -0500)]
Fix double-free when XMLSERIALIZE(... INDENT) output exceeds 1GB.

In xmltotext_with_options(), xmlSaveClose() frees the save context
unconditionally, but ctxt was only reset to NULL on the error branch.
When the close succeeded and a later step threw an error -- typically,
cstring_to_text_with_len() rejecting a result larger than MaxAllocSize
-- control reached the PG_CATCH block with ctxt still pointing at the
freed context, so xmlSaveClose() was called a second time on freed
memory and crashed the backend.

Author: Jim Jones <jim.jones@uni-muenster.de>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/bbadb6b2-d226-41a1-ace3-e0eb20648f58@uni-muenster.de
Backpatch-through: 16

2 days agoMake cache keys of other Params a Memoize subplan depends on
Richard Guo [Mon, 2 Nov 2026 01:29:02 +0000 (10:29 +0900)]
Make cache keys of other Params a Memoize subplan depends on

A Memoize node purges its whole cache whenever a Param changes which
the cache keys don't determine, such as an upper-level Param used in a
base qual of the memoized relation.  Under a correlated subquery, such
a Param changes on every invocation of the subplan, so nothing in the
cache survives from one invocation to the next.

To improve that, make cache keys of the upper-level Params found in
the memoized relation's base quals and targetlist, and on the inner
side of the join clauses, as is already done for Params buried inside
a cache key expression.  Cache entries then survive across invocations
with the same Param value.

This doesn't pay off when the Param's values don't recur across
invocations.  Cache entries for earlier values are then kept rather
than purged, and they only take up memory until the cache fills up and
evicts them.  The planner can't tell the two cases apart, as it costs
Memoize per invocation starting from an empty cache.  We accept that,
since the cache's memory is bounded by its size limit either way, and
evicting a stale entry costs about the same as purging it.

This is only an optimization, as any Param we don't find here still
purges the cache when it changes.  Hence we needn't track down every
last place a Param can appear, and a Param whose type can't be hashed
is simply left to the purging.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Yilin Zhang <jiezhilove@126.com>
Discussion: https://postgr.es/m/CA+COZaAHZT7T2G2F0-drdQB+StWJxOzqeDxp=ESp+YUiy-kOaQ@mail.gmail.com

2 days agoFix wrong results from Memoize with a Param inside a cache key
Richard Guo [Mon, 2 Nov 2026 01:28:38 +0000 (10:28 +0900)]
Fix wrong results from Memoize with a Param inside a cache key

ExecReScanMemoize() purges the whole cache only when a Param changes
which is not part of the cache key; a change to a cache-key Param is
assumed to be handled by looking up a different cache entry.  To that
end, create_memoize_plan() put every Param appearing in the cache key
expressions into keyparamids.  That assumption holds only when the
cache key values determine the Param's value.

It fails for an upper-level Param which is buried inside a larger
cache-key expression and also appears elsewhere in the subplan.  With
a cache key of "t2.hundred + t0.ten" and a filter "t1.twenty =
t0.ten", different (t2.hundred, t0.ten) pairs produce the same
cache-key value while the filter selects different rows, so one cache
entry wrongly serves both.  Since t0.ten was included in keyparamids,
the cache was never purged when it changed.

Also, pull_paramids() collected PARAM_EXTERN Params too, whose numbers
are unrelated to those of PARAM_EXEC Params.  An external Param in a
cache key could therefore keep a change to an unrelated executor Param
from purging the cache.

To fix, put into keyparamids only the Params whose values the cache
keys determine.  These are the nestloop Params which replace the outer
rel's Vars in the cache keys, as the inner scan can only reference the
outer rel through the cache keys, and, in binary mode only, a Param
which is a cache key by itself.  In logical mode the hash equality
operator may not distinguish values that affect the results
differently.  Any other Param now purges the cache when it changes.
Also make pull_paramids() collect PARAM_EXEC Params only.

Purging alone would empty the cache on every rescan of the enclosing
plan whenever a buried Param changes, even when the Param is used
nowhere else and the old code was correct and kept its cache entries
across rescans.  So also make each buried Param a cache key by itself,
which puts Memoize into binary mode, so that cache entries survive
across rescans with the same Param value.  A buried Param whose type
can't be hashed is left to the purging, rather than giving up on
Memoize.

Back-patch to all supported branches.

Reported-by: Jacob Brazeal <jacob.brazeal@gmail.com>
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Yilin Zhang <jiezhilove@126.com>
Discussion: https://postgr.es/m/CA+COZaAHZT7T2G2F0-drdQB+StWJxOzqeDxp=ESp+YUiy-kOaQ@mail.gmail.com
Backpatch-through: 14

2 days agoFix pgoutput crash on missing option values
Michael Paquier [Sun, 1 Nov 2026 23:12:27 +0000 (08:12 +0900)]
Fix pgoutput crash on missing option values

The replication protocol allows options without values, but pgoutput
dereferenced a NULL DefElem argument for parameters proto_version and
publication_names.  A replication client was able to crash a WAL sender.

This issue is fixed by reading both options with defGetString(), which
is able to report a missing parameter cleanly.

Reported-by: Brar Piening <brar@gmx.de>
Author: Zhijie Hou <houzhijie22@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Discussion: https://postgr.es/m/19795-6d7d506133b7f062@postgresql.org
Backpatch-through: 14

2 days agoMove plpython's rejection of pseudotype arguments/results.
Tom Lane [Sun, 1 Nov 2026 22:28:21 +0000 (17:28 -0500)]
Move plpython's rejection of pseudotype arguments/results.

Perform this work in the validator function, rather than repeating
it during every function call.  The previous coding not only
performed unnecessary catalog lookups during function call setup,
but failed to detect invalid argument types at CREATE FUNCTION
time if check_function_bodies is off.  That's not how that's
supposed to work.

Review of this patch exposed that we were not testing some cases
involving record-type output parameters, so add tests memorializing
the expected behavior.

In passing, fix an obsolete comment in plpython_composite.sql.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/2865288.1793403201@sss.pgh.pa.us

2 days agoFix failure in function cache entry hashing during validation mode.
Tom Lane [Sun, 1 Nov 2026 22:26:05 +0000 (17:26 -0500)]
Fix failure in function cache entry hashing during validation mode.

When cached_function_compile() is called with forValidator = true,
the passed FunctionCallInfo is one that the caller set up specially,
and it's typically pretty incomplete.  compute_function_hashkey()
was careless about this and would call get_call_result_type()
if asked to, which would fail in any but the simplest cases.
We'd managed not to notice in the pre-existing use-cases because
plpgsql and functions.c don't pass includeResultType and forValidator
both true at the same time; but plpython does, so it would reach this
failure in cases such as polymorphic argument types.  plpython does
not yet support polymorphic arguments, and has no test cases about
them, so we did not see that the intended error message had degraded
to an internal failure in get_call_result_type().

To fix, just skip trying to fill the result type tupdesc when in
validation mode.  This leads to building a hashtable entry that will
never match any real calls, but that's true in a lot of other
validation cases as well.

The root cause here is lack of clarity about what we expect the
passed FunctionCallInfo to contain in validation mode, so add
comments specifying that.  Also add some plpython test cases showing
the expected error reports.

Backpatch to v18 where funccache.c was introduced.  This problem's
not reachable in the core code in v18, since plpython didn't use
funccache.c then.  But extensions could perhaps be using funccache.c
as of v18, and they might hit it.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/2865288.1793403201@sss.pgh.pa.us
Backpatch-through: 18

2 days agomeson: Avoid PATH bloat from NLS .mo targets in tmp_install test
Andrew Dunstan [Mon, 13 Jul 2026 14:50:54 +0000 (10:50 -0400)]
meson: Avoid PATH bloat from NLS .mo targets in tmp_install test

On Windows, meson adds the build directory of every target in a test's
'depends:' to that test's PATH.  tmp_install depended on
installed_targets, which with NLS enabled includes several hundred .mo
targets, pushing PATH past the Windows length limit.  tmp_install and
initdb_cache then failed with no output.

Fix by depending on a stamp custom_target that itself depends on
installed_targets.  Meson doesn't walk a custom_target's dependencies
when building the test PATH, so this adds at most one entry.  This can
be removed once we mandate a meson version containing the upstream fix
(expected in 1.13).

Reviewed-by: Tristan Partin <tristan@partin.io>
Backpatch-through: 16
Discussion: https://postgr.es/m/CAD5tBcJXAX8bz5q9ngE4znvVLiXaPO89D0yTFhJgEPrPyT-Erw@mail.gmail.com

2 days agodoc: Add missing field description for postmaster.pid
Daniel Gustafsson [Sun, 1 Nov 2026 19:09:53 +0000 (20:09 +0100)]
doc: Add missing field description for postpid

The description mentioned that the file contains the shared memory
segment ID, but omitted the shared memory segment key which is
reported on the same line.

Author: Laurenz Albe <laurenz.albe@cybertec.at>
Reported-by: Yong Huang <yong321@yahoo.com>
Discussion: https://postgr.es/m/179313458417.1253.445225696660341760@wrigleys.postgresql.org

2 days agoReject enforcing a parent CHECK constraint over a NOT VALID child
Andrew Dunstan [Thu, 29 Oct 2026 11:21:16 +0000 (07:21 -0400)]
Reject enforcing a parent CHECK constraint over a NOT VALID child

ALTER TABLE ... ALTER CONSTRAINT ... ENFORCED on a parent's NOT ENFORCED
CHECK constraint marked the parent's constraint validated, but when it
recursed to a child whose matching constraint was already ENFORCED and
NOT VALID, it left that child alone, since its enforceability was
unchanged.  The child's existing rows were therefore never checked, and
the parent ended up validated with a child that was not.  Constraint
exclusion could then skip the child when querying the parent, and so
miss rows that violate the constraint.

Fix by raising the same error that ALTER TABLE ... INHERIT already
raises when a child has a NOT VALID copy of a parent's constraint, with
a hint to validate the child's constraint first.  Validating the child
implicitly instead was considered, but ALTER CONSTRAINT ... ENFORCED
does not validate an ENFORCED NOT VALID constraint when run directly
against the table that has it, so doing so only when reached through a
parent would be inconsistent.

Add regression tests for both regular inheritance and partitioning.

Bug introduced in 342051d73b3.

Reported-by: Shihao Zhong <zhong950419@gmail.com>
Author: Shihao Zhong <zhong950419@gmail.com>
Author: Jian He <jian.universality@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>
Discussion: https://postgr.es/m/CAGRkXqSGE=fQrjCoNQsyiCZRKfQ4SrB015CAR=3pXYB5tB=ieg@mail.gmail.com
Backpatch-through: 19

2 days agoFix incremental backup data loss due to WAL summary merge order
Fujii Masao [Sun, 1 Nov 2026 15:22:09 +0000 (00:22 +0900)]
Fix incremental backup data loss due to WAL summary merge order

An incremental backup taken after a relation is truncated and extended
again can omit modified blocks. Combining it with an earlier backup can
then restore stale data, causing live rows to disappear and deleted rows
to reappear.

WAL summaries were merged without ensuring LSN order. Applying a limit
block from an older summary after processing a newer summary could
discard references to blocks modified later, causing those blocks to
be omitted from the backup.

Sort the required summaries by ascending start LSN before merging them,
preserving references to later block modifications so that the required
blocks are included in the backup.

Backpatch to 17, where incremental backup was introduced.

Bug: #19774
Reported-by: Ke <kehan5800@gmail.com>
Author: Ke <kehan5800@gmail.com>
Co-authored-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://www.postgresql.org/message-id/19774-8a1cbfd1774fcd0c%40postgresql.org
Backpatch-through: 17

2 days agoFix WAL summary boundary checks for incremental backups.
Fujii Masao [Sun, 1 Nov 2026 15:17:17 +0000 (00:17 +0900)]
Fix WAL summary boundary checks for incremental backups.

A standby can summarize received WAL ahead of replay. If recovery ends
exactly where an old-timeline summary begins, FilterWalSummaries()
incorrectly includes that summary even though it covers only WAL outside
the promoted server's history. Truncation information in the summary
can cause an incremental backup to omit modified blocks, leading
pg_combinebackup to reconstruct files with stale data from an earlier
backup. For example, updated rows can revert to their previous values
after restoring the backup.

Fix this by excluding summaries that only touch the boundaries of the
requested LSN range without overlapping it. This makes
FilterWalSummaries() consistent with GetWalSummaries() and its existing
function comments. The old-timeline summary starting at the switch point
is thus excluded, preventing its truncation information from causing
the backup to omit required modified blocks.

Back-patch to PostgreSQL 17, where incremental backup was introduced.

Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Manu <manuelreyesbravo@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/CAJTYsWV7RThdo4K62G8hC=Anpkbr54QWbOvyVvw5uvx4+-x_DQ@mail.gmail.com
Backpatch-through: 17

3 days agoFix two crashes on a concurrently dropped schema
Heikki Linnakangas [Sat, 31 Oct 2026 11:24:50 +0000 (13:24 +0200)]
Fix two crashes on a concurrently dropped schema

pg_identify_object() looks up the object's schema name without a lock
on the schema, so a concurrent DROP SCHEMA can make get_namespace_name()
return NULL, which was then passed to quote_identifier().  Report the
schema as NULL instead, as is already done for objects that have gone
away.

Similarly, schema_to_xml() and the related SQL/XML functions look up
the schema name without a lock on the schema, and a concurrent DROP
SCHEMA can make get_namespace_name() return NULL, which was then
dereferenced.  Report that the schema does not exist, or skip it when
mapping all schemas of the database.

Author: Baji Shaik <baji.pgdev@gmail.com>
Discussion: https://www.postgresql.org/message-id/CA+fm-RPD0m9QL8W+804SGBBxn5iFz5wn=kncaP9SkM-s4PUANw@mail.gmail.com
Backpatch-through: 14

3 days agoFix PL/pgSQL error message on EOF in the middle of an expression
Heikki Linnakangas [Sat, 31 Oct 2026 10:41:41 +0000 (12:41 +0200)]
Fix PL/pgSQL error message on EOF in the middle of an expression

read_sql_construct() takes up to three terminator tokens, passing zero
for those not used.  But zero is also the token code for end of input,
so when the function body ended in the middle of an expression or
statement, the loop treated EOF as a valid terminator and stopped
there, instead of reaching the code that reports a missing terminator.
Users got a generic 'syntax error at end of input', or a misleading
'missing expression at end of input', instead of e.g. 'missing "THEN"
at end of SQL expression'.

Don't let unused terminator slots match EOF.

Author: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Discussion: https://www.postgresql.org/message-id/CAM2+6=WcWycVx0j-zw=0jFJxfazFHtZadqZbBedEg2AQkGasfQ@mail.gmail.com

3 days agoFix error handling in pg_flush_data() and FilePrefetch()
Heikki Linnakangas [Sat, 31 Oct 2026 09:24:22 +0000 (11:24 +0200)]
Fix error handling in pg_flush_data() and FilePrefetch()

posix_fadvise() returns an error code directly instead of setting
errno. However, pg_flush_data() uses %m and errcode_for_file_access()
to report errors without setting errno, potentially reporting an
unrelated error. Fix this by assigning the returned error code to
errno before reporting the error.

FilePrefetch() is documented to return an errno error code on failure,
but it returns -1 when FileAccess() fails. Fix this by returning errno
instead.

The first bug one only affects a warning, and the second doesn't have
any effect because the only existing caller ignores the return value.
So these are pretty harmless bugs, but let's be tidy.

Author: Chao Li <lic@highgo.com>
Discussion: https://www.postgresql.org/message-id/F1916C7A-F152-4AF3-87A9-40492D8B3670@gmail.com
Backpatch-through: 14

4 days agotests: Don't use the initdb template for older installations
Andres Freund [Fri, 30 Oct 2026 20:20:02 +0000 (16:20 -0400)]
tests: Don't use the initdb template for older installations

Previously the initdb template was used even when creating a Cluster.pm
instance for an old install. Obviously the current template is not right for
that case.  The only reason we didn't notice before is because the existing
cross-version tests, e.g. 002_pg_upgrade.pl, always pass initdb options for
the old node.

Oversight in 252dcb32397.

Discussion: https://postgr.es/m/xhzif5hemvslxymzhk3ykdypwqvjm7pz5dm7taizgxgfjw6fwa@6gygmz5bdnc3
Backpatch-through: 17

4 days agoRemove unused parameter from pgstat_execute_transactional_drops().
Nathan Bossart [Fri, 30 Oct 2026 19:19:29 +0000 (14:19 -0500)]
Remove unused parameter from pgstat_execute_transactional_drops().

This function's is_redo parameter has been unused since it was
introduced in commit 8b1dccd37c.  It seems unlikely that we'll ever
need to know whether we're replaying WAL here, and if we do, it's
easy enough to add it back.

Author: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/7B30D9B5-90FA-4184-85E5-60438DBE56CC%40gmail.com

4 days agoUpdate time zone data files to tzdata release 2026f.
Tom Lane [Fri, 30 Oct 2026 18:35:24 +0000 (14:35 -0400)]
Update time zone data files to tzdata release 2026f.

Cuba will not fall back on 2026-11-01; they will stay on DST this
winter (but apparently plan to revert to normal next year).

Historical corrections for Brazil.

4 days agoAdd a few recent commits to .git-blame-ignore-revs.
Nathan Bossart [Fri, 30 Oct 2026 18:10:23 +0000 (13:10 -0500)]
Add a few recent commits to .git-blame-ignore-revs.

4 days agolibpq: handle GSS credentials more sanely.
Tom Lane [Fri, 30 Oct 2026 17:56:10 +0000 (13:56 -0400)]
libpq: handle GSS credentials more sanely.

pg_GSS_have_cred_cache() always acquires new GSS credentials.
If we already had some, they were just leaked due to overwriting
conn->gcred, and that's a nontrivial amount of memory (around 16K
according to reporter).  Unfortunately, pg_GSS_continue() did this
each time through, and it is typically called more than once in a
GSSAPI connection cycle.  So repeated connections using GSS
authentication could leak substantial amounts of memory.

IMO the source of this problem is really the poorly-designed API
of pg_GSS_have_cred_cache(): it's unclear that it always gets new
credentials.  Let's rename it and remove the unnecessary pointer
parameter to make its behavior clearer.

To add insult to injury, pg_GSS_continue() shouldn't even be
trying to acquire credentials unless GSS delegation is enabled,
which it is not by default; so the whole effort is often wasted.

Problems evidently introduced by 6633cfb21, so back-patch to v16.

Bug: #19411
Reported-by: Matt Carter <Matt.Carter@twosigma.com>
Diagnosed-by: Matt Carter <Matt.Carter@twosigma.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19411-0440c8897a04b638@postgresql.org
Backpatch-through: 16

4 days agopg_stash_advice: Fix race conditions in 001_persist.pl
Robert Haas [Fri, 30 Oct 2026 16:28:59 +0000 (12:28 -0400)]
pg_stash_advice: Fix race conditions in 001_persist.pl

Each time we start the server, there's a brief lockout while the
persistence worker reloads stashes from disk. Until that's complete,
no stashes will be visible and no stash modifications can be made.
This test case failed to take that into account, and could therefore
fail spuriously.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Reported-by: Nik Samokhvalov <nik@postgres.ai>
Author: Nik Samokhvalov <nik@postgres.ai>
Co-authored-by: Robert Haas <rhaas@postgresql.org> (whitespace changes)
Backpatch-through: 19
Discussion: http://postgr.es/m/CAM527d8PqdbDy=PuTLYBJM8-FvvFDr2BLcyFyZhw6Oi9rXb14g@mail.gmail.com

4 days agoReturn INT_MAX or INT_MIN from strtoint() on overflow.
Tom Lane [Fri, 30 Oct 2026 15:03:13 +0000 (11:03 -0400)]
Return INT_MAX or INT_MIN from strtoint() on overflow.

Previously, strtoint() set errno to ERANGE on overflow but returned
the result of casting the long value to int. When the value is outside
the range of int, this produces an implementation-defined result that
cannot reliably indicate the direction of overflow.  POSIX requires
strtol() to return exactly LONG_MAX or LONG_MIN on overflow, which
permits safe sign-testing or range-testing.  By analogy, make
strtoint() return INT_MAX or INT_MIN on overflow.

Back-patch, since future bug fixes may expect this behavior.

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/A33EE17C-D014-4980-B3DD-AC51588A06EC@gmail.com
Backpatch-through: 14

4 days agoFix crash-restart race in 041_checkpoint_at_promote.pl
Fujii Masao [Fri, 30 Oct 2026 11:50:54 +0000 (20:50 +0900)]
Fix crash-restart race in 041_checkpoint_at_promote.pl

The buildfarm member bushmaster reported failures in the final test query
in 041_checkpoint_at_promote.pl with "the database system is in recovery
mode".

After killing a backend to trigger crash recovery, the test should wait
for the postmaster to terminate the remaining server processes and restart
the server, then wait for recovery to finish and connections to be accepted
before running the final query.

Previously, the test assumed that the killed backend's connection closing
meant the postmaster had noticed the crash and begun restarting. However,
the connection can close before the postmaster notices the crash. The
subsequent connection check can then succeed before recovery starts,
causing the test to mistake this for recovery having completed. The final
query could then run during recovery and fail.

Fix this by waiting for the postmaster to log that all server processes
have terminated and it is reinitializing before checking that connections
are accepted again. This ensures that the postmaster has noticed the crash
and begun restarting before the test waits for recovery to finish.

Backpatch to v17, where this test was introduced.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/e7abd282-655d-495e-94c9-e38a58917ebf@gmail.com
Backpatch-through: 17

4 days agoFix more issues with extended statistics on expressions
Michael Paquier [Fri, 30 Oct 2026 08:29:32 +0000 (17:29 +0900)]
Fix more issues with extended statistics on expressions

When evaluating expressions (through make_build_data()) and building
stats data for expressions (through build_expr_data()), both routines
forgot that examine_expression() could return a NULL result, depending
on the data generated by the typanalyze function assigned to a type.
This would crash the server.

This commit includes some tests added to test_custom_types that are able
to reproduce all these issues with two fancy typanalyze callbacks:
- False result with a valid stats target, for the expression evaluation.
- False result with a valid stats target on second call, for the stats
data build.

No typanalyze callback in core have the idea to do that, and I doubt
that anything out there has the idea to do that.  If they do, this
switches the expression stats to fail gracefully instead of crashing,
based on the combinations that are assumed as supported by the core
code.

This is a continuation of 3b7a6fa15720.

Reported-by: Yuelin Wang <1217816127@qq.com>
Author: Shihao Zhong <zhong950419@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/19763-14da3f96c02f07e8@postgresql.org
Backpatch-through: 14

4 days agoCheck all four box corners in SP-GiST quad tree <@ search
John Naylor [Fri, 30 Oct 2026 05:31:39 +0000 (12:31 +0700)]
Check all four box corners in SP-GiST quad tree <@ search

When the centroid lies outside the query box, spg_quad_inner_consistent()
keeps only the quadrants that contain a corner of the box.  It meant to
test all four corners, but the last step set x back to low.x instead of
y to low.y, so it tested (low.x, high.y) twice and never (high.x, low.y).

With exact comparisons the missing corner would not matter: a box that
does not contain the centroid lies on one side of it on at least one
axis, so (high.x, low.y) shares a quadrant with another corner, but
getQuadrant() compares with FPeq(), which tiebreaks to the lowest
numbered quadrant.

When a box edge lies within EPSILON of the centroid, the corner on that
edge counts as being on the centroid's line, and (high.x, low.y) may be
the only corner in its quadrant.  That quadrant was then skipped.  Fix
the missing corner test.

Discussion: https://postgr.es/m/CANWCAZZZpkwrX0kC4Jo6KM27J6dyBdCDir-PbjEYAS06r%3D4-ag%40mail.gmail.com
Backpatch-through: 14

5 days agoRemove unwarranted Assert in dependencies_clauselist_selectivity()
David Rowley [Fri, 30 Oct 2026 02:27:09 +0000 (15:27 +1300)]
Remove unwarranted Assert in dependencies_clauselist_selectivity()

The loop above from where the Assert is removed handles assigning the same
attnum to any duplicate expressions, so asserting there are no duplicate
attnums just after purposefully making duplicate ones isn't the correct
thing to do.

The Assert was added by a4d75c86bf, so backpatch to v14

Author: BHUVAN CHILUKUTI <c.bhuvan@iitg.ac.in>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/PN0P287MB0903563C70D8E5B81912E855A7602@PN0P287MB0903.INDP287.PROD.OUTLOOK.COM
Backpatch-through: 14

5 days agoDon't require outer joins for lateral PHV references outside subqueries
Richard Guo [Fri, 30 Oct 2026 01:49:53 +0000 (10:49 +0900)]
Don't require outer joins for lateral PHV references outside subqueries

When a rel laterally references a PHV, create_lateral_join_info() adds
the PHV's whole ph_eval_at to the rel's lateral_relids, including any
outer-join relids.  That forces those outer joins to be formed before
the rel can be joined, which join_is_legal() enforces since commit
55fa1b067.

That is necessary for a subquery.  A subquery is planned separately
and references the PHV through a single Param, so some nestloop must
supply the PHV's value as a whole, and that is only possible once the
outer joins in its ph_eval_at have been formed.

But a function, VALUES or tablesample scan does not need the PHV as a
whole.  When the outer joins in its ph_eval_at have not been formed
yet, replace_nestloop_params() recurses into the PHV's expression and
parameterizes the Vars within it, so the scan computes the expression
itself.  That gives the same answer, because the scan can only be
joined below such an outer join via outer-join identity 3, which
requires its join clause to be strict for the nullable side.  So the
rows the outer join would null-extend cannot match it anyway.  We
already rely on this for PHVs that reference other PHVs laterally,
since commit efeb12ef0.  For such rels the outer-join relids are
therefore not a real requirement, and listing them needlessly rejects
join orders that identity 3 permits.

To fix, include outer-join relids in lateral_relids only when the
referencing rel is a subquery.

No back-patch.  This is a planner improvement rather than a bug fix,
and we prefer not to change plans in stable branches.

Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAMbWs4-fcAULTpWthZMHGOFK1J+Hz=Dvr1TO-M20cC317rOGOA@mail.gmail.com

5 days agoFix nestloop parameter assignment for PHVs evaluated above outer joins
Richard Guo [Fri, 30 Oct 2026 01:49:26 +0000 (10:49 +0900)]
Fix nestloop parameter assignment for PHVs evaluated above outer joins

A NestLoop can supply a PlaceHolderVar as a parameter if the PHV can
be evaluated from the lefthand rels plus the required-outer rels of
the join.  A PHV's ph_eval_at can include outer-join relids, but
required-outer sets need not: create_lateral_join_info() keeps
outer-join relids out of the lateral dependencies it derives from
ph_lateral.  So when an outer join within ph_eval_at had been computed
by an enclosing nestloop's outer side, the test in
identify_current_nestloop_params() failed and no plan node claimed the
parameter.  This resulted in "failed to assign all NestLoopParams to
plan nodes", or, if an unrelated upper NestLoop happened to cover
ph_eval_at and claimed the parameter, "plan should not reference
subplan's variable".

To fix, have create_nestloop_plan() also count the outer joins that
have already been computed by the outer rels in scope.

Back-patch to v18, where commit a16ef313f made it possible to compute
a PHV that is used as a nestloop parameter in the outer side of the
NestLoop.  v16 and v17 can fail the same way, since ph_eval_at has
included outer-join relids since v16, but they lack that machinery.
Fixing them would mean adding join-order restrictions to
have_dangerous_phv() that could change plans that work today, which
does not seem worth the risk for a failure this unlikely.

Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAMbWs4-fcAULTpWthZMHGOFK1J+Hz=Dvr1TO-M20cC317rOGOA@mail.gmail.com
Backpatch-through: 18

5 days agoFix twophase recovery log matching with verbose logs
Fujii Masao [Fri, 30 Oct 2026 01:18:21 +0000 (10:18 +0900)]
Fix twophase recovery log matching with verbose logs

Commit c11eb5de01b added checks for prepared transaction recovery
messages in 009_twophase.pl that assumed no SQLSTATE appeared after
the log severity. With log_error_verbosity=verbose, the SQLSTATE is
included, causing the positive checks to fail and preventing the
negative checks from detecting unwanted LOG messages.

Allow an optional SQLSTATE in all five checks.

Per buildfarm member prion, which uses log_error_verbosity = verbose.

Reported-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/2256937.1793317544@sss.pgh.pa.us

5 days agoFix poorly-formatted comment.
Tom Lane [Thu, 29 Oct 2026 21:46:24 +0000 (17:46 -0400)]
Fix poorly-formatted comment.

Per buildfarm member koel.

5 days agoFix issue with code manually adjusting a TupleTableSlot
David Rowley [Thu, 29 Oct 2026 20:49:59 +0000 (09:49 +1300)]
Fix issue with code manually adjusting a TupleTableSlot

c456e3911 changed how tuple deforming populates the slot's tts_isnull
array.  This is now done 8 columns at a time instead of 1 column at a
time.  That code also now deforms the tuple's entire NULL bitmap on each
incremental deform, where previously only the tts_isnull elements for
newly deformed attributes got set.  This caused problems for grouping
sets queries.

In prepare_projection_slot() when grouped_cols was non-empty, the code
would manually put "true" into the grouped column's tts_isnull element to
represent the NULL for grouping sets which don't include that column.
This was incompatible with the post-c456e3911 complete fresh of previously
deformed tts_isnull elements, as if any further attributes needed to be
deformed after the NULLs were manually placed, the deforming code would
overwrite those NULLs.

Here we fix this by changing the slot_getsomeattrs() call to always
deform everything we need for this tuple.  That means there will be no
additional tuple deforms for this tuple.

Bug: #19783
Reported-by: Alperen Keles <alpkeles99@gmail.com>
Author: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/19783-070e4bf0c73c1076@postgresql.org
Backpatch-through: 19

5 days agopg_stash_advice: Don't forget unsaved changes after a failed write.
Robert Haas [Thu, 29 Oct 2026 16:37:07 +0000 (12:37 -0400)]
pg_stash_advice: Don't forget unsaved changes after a failed write.

If the persistence worker hits an error while writing
pg_stash_advice.tsv, it exits and the postmaster restarts it. The new
worker doesn't think the file needs to be rewritten until something
changes or the server shuts down. Instead, it should retry the failed
write.

This also fixes a second bug. The worker should record the current
change count before, rather than after, setting stashes_ready.
Failure to do so creates a narrow window during which any changes
won't trigger the persistence worker to rewrite the file.

Zsolt's original patch included a test case, but I've left that out
here because it doesn't seem worth the cycles for a bug that seems
unlikely to be reintroduced. If others disagree, we can revisit.

Oversight in commit c10edb102ada607eb054bc9e23690109d86849ef.

Reported-by: Zsolt Parragi <zsolt.parragi@percona.com>
Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Dongpo Liu <poe.liu@pm.me>
Discussion: http://postgr.es/m/CAN4CZFMoWWdXhrNRk1id=N_K4o5kae3kQTtJi__UfzrEOeUCCA@mail.gmail.com
Backpatch-through: 19

5 days agopg_plan_advice: Mark PARTITIONWISE inapplicable on plain rels.
Robert Haas [Thu, 29 Oct 2026 15:35:49 +0000 (11:35 -0400)]
pg_plan_advice: Mark PARTITIONWISE inapplicable on plain rels.

Previously, such advice was accepted, and just had the effect of disabling
every path for the target relation, which isn't the worst imaginable
behavior, but it's not difficult to do better. This commit causes such
advice to instead be marked inapplicable, like INDEX_SCAN(some_table
NO_SUCH_INDEX).

One advantage of this change is that it improves the test coverage
provided by test_plan_advice. In fact, prior to commit
0f7dfd7936b9e99f9aeca00f52ab1692898ffff4, these changes caused
test_plan_advice failures, because the defect fixed by that commit
caused PARTITIONWISE advice to target the wrong relations. Without
this change, the advice feedback doesn't show any sign that there's
a problem, which is how that defect escaped discovery.

Reported-by: Nikolay Samokhvalov <nik@postgres.ai>
Discussion: http://postgr.es/m/CA+Tgmob3X+_CSjAa_BtU9bXrX_ge_HyvO=7gSCLtBpncGwn-kQ@mail.gmail.com
Tested-by: Jakub Wartak <jakub.wartak@enterprisedb.com>
Backpatch-through: 19

5 days agopg_plan_advice: Suppress advice from unflattened set operations.
Robert Haas [Thu, 29 Oct 2026 14:56:10 +0000 (10:56 -0400)]
pg_plan_advice: Suppress advice from unflattened set operations.

Previously, we could generate GATHER, GATHER_MERGE, or NO_GATHER
advice for portions of the plan tree generated by set operation
planning. There are no upper-planner hooks we can use to enforce
such advice, so we shouldn't generate it, either. Make it so, and
also add a bunch of test cases to verify the behavior.

Reported-by: Nikolay Samokhvalov <nik@postgres.ai>
Discussion: http://postgr.es/m/CA+Tgmob3X+_CSjAa_BtU9bXrX_ge_HyvO=7gSCLtBpncGwn-kQ@mail.gmail.com
Tested-by: Jakub Wartak <jakub.wartak@enterprisedb.com>
Backpatch-through: 19

5 days agoReduce log verbosity during prepared transaction recovery
Fujii Masao [Thu, 29 Oct 2026 14:09:38 +0000 (23:09 +0900)]
Reduce log verbosity during prepared transaction recovery

Previously, RecoverPreparedTransactions() logged each prepared
transaction at LOG level at the end of recovery. With many unresolved
prepared transactions, these messages could clutter the server log.

Lower the severity of these messages to DEBUG2, matching the messages
in PrepareRedoAdd() and PrepareRedoRemoveFull(), and report the
number of successfully recovered prepared transactions in a single
LOG message. This reduces log clutter while retaining per-transaction
details at DEBUG2.

Author: Ashutosh Sharma <ashu.coek88@gmail.com>
Reviewed-by: Jakub Wartak <jakub.wartak@enterprisedb.com>
Reviewed-by: Pierre Forstmann <pierre.forstmann@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAE9k0Pmq1qQEvTKqsBTwUAWrNw+191zcTBPVKmmP5E3X2C+_Xw@mail.gmail.com

5 days agoUse pg_parse_lsn() to parse LSN fields in backup_label
Fujii Masao [Thu, 29 Oct 2026 11:45:29 +0000 (20:45 +0900)]
Use pg_parse_lsn() to parse LSN fields in backup_label

The START WAL LOCATION and CHECKPOINT LOCATION fields in backup_label
accepted overlong high components, which could overflow and produce a
different LSN from the one supplied.

Use pg_parse_lsn() to validate and convert these fields, requiring one
to eight hexadecimal digits per component and no trailing characters,
as for pg_lsn input.

Also detect INCREMENTAL FROM LSN without parsing its value, so that
malformed values such as "junk" do not bypass the existing check
against using an incremental backup directly as a data directory.

Author: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Jan Nidzwetzki <jan@planetscale.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/OS7PR01MB18317EED85B1A72C69B226630F5672@OS7PR01MB18317.jpnprd01.prod.outlook.com

5 days agoFix eager aggregation below volatile join clauses
Richard Guo [Thu, 29 Oct 2026 06:32:40 +0000 (15:32 +0900)]
Fix eager aggregation below volatile join clauses

Eager aggregation could push a partial aggregation down to a relation
that is later joined using a join clause containing volatile
functions.  The clause is then evaluated once per group rather than
once per input row, which changes the number of times the function is
executed.

To fix, refuse to build grouped paths for a relation if any of its
join clauses contains volatile functions.

Back-patch to v19, where eager aggregation was introduced.

Author: shihao zhong <zhong950419@gmail.com>
Reviewed-by: Manu <manuelreyesbravo@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqSc_qtpuPm34qoS1z0LVx4+Hc+JcJkbDEVC=z2ai4VQ1w@mail.gmail.com
Backpatch-through: 19

5 days agoEmpty partial_pathlist when unsetting consider_parallel flag
David Rowley [Thu, 29 Oct 2026 03:19:49 +0000 (16:19 +1300)]
Empty partial_pathlist when unsetting consider_parallel flag

It's not valid for a RelOptInfo to have a non-empty partial_pathlist
when its consider_parallel is true.  In set_append_rel_pathlist() when
we see the parent rel doesn't have consider_parallel set, we set that
property to false for the child.  It is possible that the child already
has some partial paths at that point, so we need to nullify that list as
well as set the consider_parallel flag to false.

For the reported problem case, the partial paths had been created during
set_subquery_pathlist().  These not being empty was causing an Assert
failure on cassert builds.  I think this could only have gone on to
result in some wasted planner effort in non-cassert builds, but cannot
confirm if anything worse could have happened.

Bug: #19803
Reported-by: Gowtham Reddy <gowthamdoma18@gmail.com>
Author: David Rowley <dgrowleyml@gmail.com>
Tested-by: Gowtham Reddy <gowthamdoma18@gmail.com>
Discussion: https://postgr.es/m/19803-1fcc1df108c54ab6@postgresql.org
Backpatch-through: 14

6 days agoDon't replace clone clauses with constant TRUE
Richard Guo [Thu, 29 Oct 2026 02:27:12 +0000 (11:27 +0900)]
Don't replace clone clauses with constant TRUE

When reconsider_outer_join_clauses() finds an outer-join clause
OUTERVAR = INNERVAR whose OUTERVAR is known to equal a constant, it
pushes INNERVAR = CONSTANT into the inner side and replaces the clause
with constant TRUE.  The replacement assumes that OUTERVAR cannot have
gone to NULL where the clause is evaluated.

That assumption fails for a clone made for outer join identity 3.
When an outer join is pushed into the RHS of a lower outer join, its
relid is not added to the joinrel until the commuted pair is complete,
so a version of a clause that lacks that join's nulling bit can be
applied above it, after it has null-extended OUTERVAR.  This is fine
for the original clause, because it is strict, which is what allowed
the commutation in the first place; but it is not fine for constant
TRUE.  As a result, inner rows could be joined to null-extended outer
rows, producing wrong query results.

To fix, throw back a clone as-is rather than the TRUE replacement, as
v15 and earlier did.  The derived INNERVAR = CONSTANT clause remains
valid and is still pushed down.  This can leave a redundant join
filter in some plans, as seen in an existing regression test.

To keep the thrown-back clause from affecting selectivity estimates,
including for parameterized scans, where the cached selectivity is not
used, restore the redundancy marker removed by b448f1c8d: a norm_selec
greater than 1 marks a redundant clause, for which
clause_selectivity_ext() always returns 1.0.

Back-patch to v16, where clone clauses were introduced.

Bug: #19765
Reported-by: Viktor Leis <leis@in.tum.de>
Diagnosed-by: Tender Wang <tndrwang@gmail.com>
Author: Richard Guo <guofenglinux@gmail.com>
Co-authored-by: Nitin Motiani <nitinmotiani@google.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Discussion: https://postgr.es/m/19765-5778b18918040583@postgresql.org
Backpatch-through: 16

6 days agoDo not take a full-page image for REGBUF_NO_CHANGE buffers
Michael Paquier [Thu, 29 Oct 2026 02:13:44 +0000 (11:13 +0900)]
Do not take a full-page image for REGBUF_NO_CHANGE buffers

A buffer registered with REGBUF_NO_CHANGE is not modified by the record
and, in the case of the hash index AM, may be held with only a pin (no
content lock).  The hash index code registers the primary bucket page
this way in hashbucketcleanup(), _hash_freeovflpage() and
_hash_squeezebucket(), solely to force a cleanup lock on that block
during replay.

When wal_consistency_checking includes "hash", XLogRecordAssemble()
included a full-page image for block only pinned, because
XLR_CHECK_CONSISTENCY forces an image regardless of REGBUF_NO_IMAGE.
The record CRC is then computed over the image while a concurrent
backend, which legitimately holds nothing stronger than a pin
on that page, could modify it before the record is copied into the WAL
buffers.  This would result is an intermittent "incorrect resource
manager data checksum in record" failure on a standby.

As of this commit, never take an image for a REGBUF_NO_CHANGE buffer,
even under XLR_CHECK_CONSISTENCY.  There is no need to do a consistency
check on a block not changed by a record.  verifyBackupPageConsistency()
is taught to skip a registered block that carries no image rather than
asserting one should be present.

REGBUF_NO_CHANGE exists since 00d7fb5e2e39, so backpatch down to v17.
On older branches, the CRC problem can be reproduced as well, but we
lack the mechanism to check how a buffer is handled by the code
assembling a record.  Per discussion, the long term picture should be to
fix the hash index AM so as REGBUF_NO_CHANGE is removed.  This would be
a HEAD-only change.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Diagnosed-by: Thomas Munro <thomas.munro@gmail.com>
Author: Greg Burd <greg@burd.me>
Discussion: https://postgr.es/m/ats4pi-RM0Uom0T9@floki
Backpatch-through: 17

6 days agoFix JSON_TABLE with sublinks in PASSING arguments
Amit Langote [Thu, 29 Oct 2026 01:38:48 +0000 (10:38 +0900)]
Fix JSON_TABLE with sublinks in PASSING arguments

transformJsonTable() handed the raw PASSING argument list both to the
JsonFuncExpr built for the row pattern and, via
transformJsonTableColumn(), to the JsonFuncExpr built for each column
other than FOR ORDINALITY, so the same raw expressions were run through
transformExpr() once for the row pattern and again for every such
column.  That doesn't work for sublinks: transformSubLink() replaces
the SubLink's raw subselect with the analyzed Query, so the second
pass failed with "unexpected non-SELECT command in SubLink".  Other
nodes that are transformed in place, such as NullTest, failed with
"unrecognized node type".  Any such PASSING argument therefore made
JSON_TABLE fail unless all of its columns were FOR ORDINALITY.

Fix by giving each transformation its own copy of the raw PASSING
arguments.

Bug: #19786
Reported-by: Alperen Keles <alpkeles99@gmail.com>
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Co-authored-by: Amit Langote <amitlangote09@gmail.com>
Discussion: https://postgr.es/m/19786-70758103a4b2bff2@postgresql.org
Backpatch-through: 17

6 days agoSQL/JSON: fix error handling when coercing to a domain fails softly
Amit Langote [Thu, 29 Oct 2026 00:36:38 +0000 (09:36 +0900)]
SQL/JSON: fix error handling when coercing to a domain fails softly

SQL/JSON query functions could throw an error, or report the wrong one,
in cases where the ON ERROR or ON EMPTY clause said what to do instead.
This happened when the RETURNING type, or a DEFAULT expression,
involved a domain: if the value failed to convert to the domain's base
type, that failure was saved to be handled by the ON ERROR behavior,
but the domain's constraints were then checked anyway, against the
dummy NULL left behind by the failed conversion.  A CHECK expression
can throw a hard error on that NULL, which ON ERROR cannot catch, and
a NOT NULL constraint reports a violation that overwrites the saved
error, so the error message ends up describing the wrong problem.

For example, this failed with "division by zero" instead of returning
11:

  CREATE DOMAIN d AS int CHECK (1 / coalesce(VALUE, 0) = 0);
  SELECT JSON_VALUE(jsonb '"x"', '$' RETURNING d DEFAULT 11 ON ERROR);

Fix by stopping as soon as a soft error has been saved, in each of the
places that kept going:

* The domain constraint checks of a CoerceToDomain in an ON ERROR or ON
  EMPTY DEFAULT expression, which is the only case where they are
  evaluated softly.  ExecInitCoerceToDomain now emits a jump before each
  constraint check that skips the remaining checks if an error has
  already been saved.

* populate_domain, called from json_populate_type when coercing to a
  domain.  Return as soon as the conversion to the base type fails,
  instead of going on to check the domain's constraints.

* populate_record, likewise.  Stop populating the remaining columns as
  soon as one of them fails.

* ExecEvalJsonCoercion.  Return at once if the DEFAULT expression whose
  result it would coerce has already failed, and leave throwing the
  error to the COERCION_FINISH step that follows.

Reported-by: jian he <jian.universality@gmail.com>
Author: jian he <jian.universality@gmail.com>
Discussion: https://postgr.es/m/CACJufxHDK39zF+1zZF6prH_wtn1SDt74_mrqYk1Oo82cCu44ng@mail.gmail.com
Backpatch-through: 17

6 days agoWork around failure with SPARC in base backup code
Michael Paquier [Thu, 29 Oct 2026 00:43:12 +0000 (09:43 +0900)]
Work around failure with SPARC in base backup code

As reported by buildfarm members thorntail and billbug, both running
SPARC, 4a92c8c29bd0 is making the base backup code unstable on such
platforms.

The only suspicion I have at this stage is a stack frame issue, pointing
to something unrelated to 4a92c8c29bd0, that the addition of an array
worth a size of PG_CONTROL_FILE_SIZE within perform_base_backup() is
able to trigger.

thorntail complained with a SIGBUS, pointing at misaligned access, with
a sporadic failure.  billbug complained with a SIGSEGV (siglongjmp issue
with PG_ENSURE_ERROR_CLEANUP perhaps?) in a more stable fashion.

The code is changed to use a palloc0() instead, which should cool down
the problem with the stack, hopefully.  Unfortunately, I could not test
this hypothesis directly, lacking an environment able to do so.

Discussion: https://postgr.es/m/auGYf3jXtzLrr4gA@paquier.xyz
Backpatch-through: 15

6 days agoSQL/JSON: always rethrow soft errors from DEFAULT expressions
Amit Langote [Thu, 29 Oct 2026 00:15:19 +0000 (09:15 +0900)]
SQL/JSON: always rethrow soft errors from DEFAULT expressions

The DEFAULT expression of an ON ERROR or ON EMPTY clause is compiled
with the JsonExpr's ErrorSaveContext in effect, so that any error
raised while evaluating it is saved rather than thrown and can be
reported later as "could not coerce ON ERROR expression (DEFAULT) to
the RETURNING type". That reporting is done by an
EEOP_JSONEXPR_COERCION_FINISH step, but ExecInitJsonExpr only added
that step when the DEFAULT expression needed a runtime coercion, or
when its top-level node was a CoerceViaIO or a CoerceToDomain.  Those
are not the only nodes that can save an error: the ErrorSaveContext
applies to the whole expression tree, so a cast nested inside, say,
an OpExpr saves its error just the same.  In that case there was
nothing to rethrow it and the query silently returned NULL instead
of failing, for example:

  SELECT JSON_VALUE('"a"', '$' RETURNING int
                    DEFAULT (('a' || (random() * 0)::int)::int + 0)
                    ON ERROR);

Fix by adding the COERCION_FINISH step after every DEFAULT expression
that is evaluated softly, that is, whenever the ON ERROR behavior is
not ERROR.

Reported-by: jian he <jian.universality@gmail.com>
Author: jian he <jian.universality@gmail.com>
Discussion: https://postgr.es/m/CACJufxHDK39zF+1zZF6prH_wtn1SDt74_mrqYk1Oo82cCu44ng@mail.gmail.com
Backpatch-through: 17

6 days agopg_plan_advice: Fix multiple problems with NO_GATHER advice.
Robert Haas [Wed, 28 Oct 2026 19:04:05 +0000 (15:04 -0400)]
pg_plan_advice: Fix multiple problems with NO_GATHER advice.

First, the documentation describes NO_GATHER in a way that suggests
that it should both suppress partial path generation and also prohibit
the placement of Gather and Gather Merge within a join problem, but in
fact it only did the latter. Change it to do the former as well. Like
commit f71a9969d58e3e70239fc51bbeae668db973b265, this is fallout from
my failure to realize everything that needed to be changed when I
abandoned the idea of clearing consider_parallel as a way to suppress
parallel paths.

Second, emit NO_GATHER advice for the non-partial children of a
Parallel Append, because we want exactly the behaviors described
above for that case. In order to reproduce the Parallel Append, we'll
need an entirely non-parallel path for that child.

Third, update the documentation to be more precise about what happens
when NO_GATHER is applied to a child table. I believe I intended this
to work in the way described in the first paragraph above, but because
of the omission noted there, it had no effect at all. Moreover, the
documentation described the two different effects of NO_GATHER as if
subqueries were the only relevant case, but partitioning or table
inheritance gives rise to similar effects, so clarify accordingly.

Discussion: http://postgr.es/m/CA+Tgmob3X+_CSjAa_BtU9bXrX_ge_HyvO=7gSCLtBpncGwn-kQ@mail.gmail.com
Tested-by: Jakub Wartak <jakub.wartak@enterprisedb.com>
Backpatch-through: 19

6 days agoRemove the redundant interface list and fix function headings in predicate.c
Fujii Masao [Wed, 28 Oct 2026 08:02:19 +0000 (17:02 +0900)]
Remove the redundant interface list and fix function headings in predicate.c

The interface list duplicates declarations in the headers and has
accumulated stale signatures and missing entries. Remove it rather
than maintaining a separate copy of the declarations.

Also correct the headings above AtPrepare_PredicateLocks() and
PostPrepare_PredicateLocks(), which incorrectly name the separate
AtPrepare_Locks() and PostPrepare_Locks() functions.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Aleksander Alekseev <aleksander@tigerdata.com>
Discussion: https://postgr.es/m/CAHGQGwHww5o8abim0DGVFNb5bBre2a+V1twhH2cu-J21rYGcaQ@mail.gmail.com

6 days agoRemove unused PageIsPredicateLocked()
Fujii Masao [Wed, 28 Oct 2026 08:01:45 +0000 (17:01 +0900)]
Remove unused PageIsPredicateLocked()

The last caller of PageIsPredicateLocked(), an assertion in B-tree
VACUUM, was removed in commit 47ad79122bc, leaving the function unused.

Remove its implementation, declaration, and entry in the list of
predicate locking interface routines.

Author: Aleksander Alekseev <aleksander@tigerdata.com>
Reviewed-by: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reviewed-by: Pierre Forstmann <pierre.forstmann@gmail.com>
Reviewed-by: solai v <solai.cdac@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAJ7c6TMCOi-TTfPSWh+wxkOMgqcvoG-FCWPU1iGCfrmA2JOajQ@mail.gmail.com

6 days agoFix stale pg_index flags in the relcache for TOAST indexes
Michael Paquier [Wed, 28 Oct 2026 05:21:59 +0000 (14:21 +0900)]
Fix stale pg_index flags in the relcache for TOAST indexes

RelationReloadIndexInfo() re-reads the mutable pg_index fields
(indisready, indisvalid, indislive, etc.) only for indexes that are
not system relations.  The TOAST index of a user table lives in
pg_toast and counts as one, but REINDEX CONCURRENTLY changes these
fields on it like on any other index.

A backend that had the TOAST indexes open when the invalidation
arrived kept indisready = false for the new index, and did not insert
its chunks there.  Once the old index is dropped, reading such a value
fails with "missing chunk number 0 for toast value N in pg_toast_X".
The chunks remain in the TOAST table, only the index references were
gone, so a rebuild of the TOAST index would fix this issue.

This issue is fixed by re-reading the pg_index row for TOAST indexes,
filling in their relcache fields.  This is the same as for an index on a
user table.  Previouly, IsSystemRelation() was used, meaning the
pg_index data was not re-read for a TOAST relation or a relation with a
pinned OID (created by initdb).  This check is meant for indexes whose
values never change, so IsCatalogRelation() is fine, implying that only
indexes created by initdb should be skipped (REINDEX CONCURRENTLY does
not work on catalogs).

This code is as old as 8ec943856a4, and was only used for CREATE INDEX
CONCURRENTLY.  5dc92b844e68, that has introduced REINDEX CONCURRENTLY,
has made possible to reach the problem with TOAST indexes due to these
getting concurrently built, validated and then swapped.

A test is added, able to reproduce the issue.  It forces an insert
before a swap, with a second session that maintains the TOAST indexes
open while the new index becomes ready.  This has been slightly
simplified by me compared to what the author has sent.

Oversight in 5dc92b844e68.

Reported-by: Saicharanreddy Chinthareddy <saicharh@amazon.com>
Author: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CALj2ACUAv=7wjOV3pRFhQP4WHME_JazuhoCr01i4_F2XA=JKog@mail.gmail.com
Backpatch-through: 14

7 days agoDetect overflows in various numerical aggregate transfns
David Rowley [Wed, 28 Oct 2026 00:25:21 +0000 (13:25 +1300)]
Detect overflows in various numerical aggregate transfns

Here we add overflow checks to guard against overflowing the int8 sum of
all inputs for sum(int2), sum(int4), avg(int2) and avg(int4).  Such an
overflow is very unlikely for the int2 versions, but somewhat possible
to hit for the int4 versions when given billions of large enough inputs.
Since our code and machines are getting faster, and with the advent of
things like columnar table AMs, it's getting more likely that such an
overflow could occur in a real use case.

No guards have been added to the average count.  That would require 2^63
input rows, which is not possible to achieve in a single instance of
PostgreSQL, given other limitations such as 64-bit LSNs.

Fixing this only in master as we can probably get away with that today
due to this still being unlikely for users to ever hit.

Author: Andrei Lepikhov <lepihov@gmail.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/1ddc2a6f-4b26-43d9-9f3b-5b5db98a486d@gmail.com

7 days agoAvoid torn copy of the control file in base backups
Michael Paquier [Tue, 27 Oct 2026 23:42:35 +0000 (08:42 +0900)]
Avoid torn copy of the control file in base backups

Base backups read the control file (pg_control) from disk without any
protection against concurrent writes by the server, making it exposed to
torn copies.  Attempting to use such a control file at startup would
cause a failure with a CRC not matching.

Base backups now read the control file while holding ControlFileLock.
c558e6fd92f has done the same for some SQL functions.  The contents of
the file are saved in memory and sent over the wire as-is.

Backpatch down to v15.  This issue is older than v15 but v14 is left out
of the picture as it is going to be EOL soon, so it does not seem worth
taking a risk for.

Author: David Steele <david@pgbackrest.org>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/d1697de1-eb7f-41bf-a4b7-bba7203df11f@pgbackrest.org
Backpatch-through: 15

7 days agoFix broken indentation caused by 34d52e6d3
David Rowley [Tue, 27 Oct 2026 22:42:22 +0000 (11:42 +1300)]
Fix broken indentation caused by 34d52e6d3

Per buildfarm member koel

Backpatch to 19 to avoid unnecessary variations.

Backpatch-through: 19

7 days agoAdd PG_RETURN_ARG macro and use it for sum(int2) and sum(int4)
David Rowley [Tue, 27 Oct 2026 21:36:38 +0000 (10:36 +1300)]
Add PG_RETURN_ARG macro and use it for sum(int2) and sum(int4)

This is intended for SQL-level functions written in C for cases when
they want to return an input parameter unmodified; NULL if that parameter
is NULL, or the exact value of the parameter otherwise.  The return type
and the given input parameter must have matching types.  The caller must
verify whether it's safe to not copy non-byval types and not de-toast
variable-length typed inputs.

Here we introduce two usages of the new macro for the transition
functions for sum(int4) and sum(int2).  These just need to return the
int8 aggregate state value unmodified when asked to transition a NULL
input; the aggregate state may or may not be NULL at that point.
PG_RETURN_ARG() is coded to work for either case.

This is primarily being added to partially circumvent an argument
against adding overflow checks on sum(int2) and sum(int4), which a pending
patch proposes to do.  Effectively, here we're removing 1 jump per
transition function, and that commit plans to add a new jump, so this
commit allows a net zero increase in jumps for both of those functions.

Author: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAApHDvp-3v1OWbo7RavBf37=MjNScqhj4vyAyHOUDY51nGUnog@mail.gmail.com

7 days agoFix deparsing of AT TIME ZONE and similar as FROM-clause functions.
Tom Lane [Tue, 27 Oct 2026 21:24:02 +0000 (17:24 -0400)]
Fix deparsing of AT TIME ZONE and similar as FROM-clause functions.

ruleutils.c's looks_like_function() assumed that all COERCE_SQL_SYNTAX
cases produce output that looks like a function call (or at least
like one of the syntaxes the func_expr_windowless production accepts).
But AT TIME ZONE, AT LOCAL, OVERLAPS and IS xxx NORMALIZED print as
other sorts of a_expr, so those cases would produce invalid SQL syntax
when used in a FROM clause.  Extend the logic to detect which specific
functions are safe or unsafe.

Author: Henson Choi <assam258@gmail.com>
Reviewed-by: Prashant Chinnam <crprashant@hotmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAAAe_zC68s-DwVX1o7C1HVcRk+Z+RTS6Vw19auZFfz=KaX8tZA@mail.gmail.com
Backpatch-through: 14

7 days agoReintroduce hash_mem cap on buckets in BuildTupleHashTable
David Rowley [Tue, 27 Oct 2026 20:06:30 +0000 (09:06 +1300)]
Reintroduce hash_mem cap on buckets in BuildTupleHashTable

8f29467c5 removed the hash_mem cap from the nbuckets calculation in
BuildTupleHashTable() and put the trust into the planner to provide that
function with a sane value, which it would only cap at 2^32.  There are
various places in the planner which cannot provide good estimates here
and it's been demonstrated that it's not difficult to craft a query
which requests 2^32 buckets.

Here we reintroduce the sanity checks so we don't end up making the hash
table's initial size to something that would exceed hash_mem.  This may
cause the hash table to have to grow several times before it fills, but
that seems much better than having the executor OOM due to the request
being too large.  Users are also used to work_mem and
hash_mem_multiplier having an effect on query performance, so this
shouldn't be too surprising.  It also restores the limits that were
imposed pre-8f29467c5, which were tried and tested.

Bug: #19759
Reported-by: Alperen Keles <alpkeles99@gmail.com>
Author: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/19759-acd3f33402e54f36@postgresql.org
Backpatch-through: 19

7 days agodoc: Add note about promotion waits on backends stuck sending to clients.
Masahiko Sawada [Tue, 27 Oct 2026 18:13:04 +0000 (11:13 -0700)]
doc: Add note about promotion waits on backends stuck sending to clients.

Commit df1be4ddc83 made promotion skip waiting for the barrier that
refreshes each process's cached logical WAL logging state in some
cases, but promotion still waits for it on a standby with wal_level =
replica that has a valid logical slot. A backend blocked sending data
to a client that has stopped reading can't process the barrier, so
promotion can wait for a long time.

Add a note about this case in the failover section, along with ways to
get out of the wait and to bound it in advance.

Backpatch to v19, where commit 67c20979ce7 introduced this wait.

Author: shihao zhong <zhong950419@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Zhijie Hou <houzhijie22@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqToBk9c2sPAgha-kCgxJhVwn90j1sCyUXrvydq51LKAqA@mail.gmail.com
Backpatch-through: 19

7 days agoDisallow NOT NULL NO INHERIT constraints on partitioned tables
David Rowley [Tue, 27 Oct 2026 06:46:12 +0000 (19:46 +1300)]
Disallow NOT NULL NO INHERIT constraints on partitioned tables

This was blocked during normal CREATE TABLE, but cases such as CREATE
TABLE (LIKE) would copy the source table's NOT NULL NO INHERIT constraints
and apply them to the partitioned table being created.  This could mean
that partitions didn't correctly receive the NOT NULL constraint when they
were created, thus could contain NULL values.

cacef1722 added a test to ensure CREATE TABLE (LIKE) PARTITION BY fails
when the source table has any CHECK NO INHERIT constraints.  Here we do
the same for NOT NULL constraints.

It's probably unlikely that people have commonly done this, but the
release notes may wish to note that people should check if this has
happened to them.  The following query can used each database to identify
problematic constraints:

SELECT conrelid::regclass, conname, connoinherit
FROM pg_constraint
WHERE contype = 'n'
  AND connoinherit = true
  AND conrelid IN (SELECT oid FROM pg_class WHERE relkind = 'p');

If no results are shown, the queried database isn't affected.

To resolve these issues, unwanted constraints can simply be dropped from
the partitioned table with:

ALTER TABLE ... DROP CONSTRAINT ...;

To remove the NO INHERIT flag, use:

ALTER TABLE ... ALTER CONSTRAINT ... INHERIT;

This will fail if any partition contains a NULL value in the given
column.  Finding the cause of failures is made more difficult by the
planner trusting that "WHERE col IS NULL" cannot be true because of the
presence of a NOT NULL constraint.  Affected users may need to resort to
tricks like WHERE col+0 IS NULL to find these.  If it was thought to be a
common problem, then we could adjust get_relation_notnullatts(), and the
equivalent functions on older branches to ignore constraints marked as NO
INHERIT on partitioned tables, but currently that would require an
expensive lookup to find the pg_constraint row.

Backpatch to v18 where NOT NULL NO INHERIT constraints were added by
14e87ffa5.

Bug: #19770
Reported-by: Ann C <anncalla@163.com>
Author: David Rowley <dgrowleyml@gmail.com>
Author: Nitin Motiani <nitinmotiani@google.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Nitin Motiani <nitinmotiani@google.com>
Discussion: https://postgr.es/m/19770-7c6e75fc30df7e06@postgresql.org
Discussion: https://postgr.es/m/CAH5HC96YCzOy+9JZLQ4n0sMchVnharTOXrr4sbYuh=_d+ffjAA@mail.gmail.com
Backpatch-through: 18

7 days agopg_stat_statements: Fix toplevel tracking across nesting levels
Michael Paquier [Tue, 27 Oct 2026 06:17:17 +0000 (15:17 +0900)]
pg_stat_statements: Fix toplevel tracking across nesting levels

pg_stat_statements decides whether a query is toplevel from the
nesting level at the time each hook runs.  A QueryDesc can outlive the
level it started at.  For example, a cursor's query starts at level 1,
inside DECLARE, but if the cursor is closed implicitly at COMMIT,
ExecutorEnd runs at level 0.  The entry created for the query at parse
analysis has toplevel = false, so ExecutorEnd misses it and stores a
duplicate with the raw query text and toplevel = true.

The same happens with track = top when another extension such as
auto_explain requests query instrumentation.  ExecutorEnd stores the
query even though ExecutorStart did not track it.

PGSS is upgraded to save the nesting level in the extension state of the
QueryDesc when ExecutorStart() tracks a query.  ExecutorEnd() then uses
it in place of the current level and skips the query if no state was
saved.

For now, only the nesting level is tracked in the private extension
state attached to QueryDesc by PGSS.  auto_explain is not touched
either.  All these pieces are left as future improvements.

No backpatch is done, due to the ABI changes required in QueryDesc.
This relies on the work done previously in e5d5d1ad1e3a.

Reported-by: Gaurav Singh <gaurav.singh@yugabyte.com>
Author: Sami Imseih <samimseih@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAEcQ1bZrgwKsauC=03otebkLk77Zc_hYNjhTP3OUdpXs++u+BA@mail.gmail.com
Discussion: https://postgr.es/m/CAA5RZ0v281uwSudcFrY8BymSRDM4J6PAHfzqg_9R+i7zWbTb2A@mail.gmail.com

7 days agoAdd custom extension states to QueryDesc
Michael Paquier [Tue, 27 Oct 2026 06:05:59 +0000 (15:05 +0900)]
Add custom extension states to QueryDesc

Extensions sometimes need to carry private data from one executor hook
to another for a given query.  ExecutorEnd() can run in a different
context than ExecutorStart(), so backend-wide variables cannot be used
for that.

This commit adds a way for loadable modules to attach private state to a
QueryDesc, modeled in the same fashion as what is already done for
PlannerGlobal, PlannerInfo, RelOptInfo and ExplainState.

GetQueryDescExtensionId() maps an extension name to a backend-local ID.
SetQueryDescExtensionState() and GetQueryDescExtensionState() store and
fetch an opaque pointer for that ID.  The array of pointers is allocated
in the memory context of the QueryDesc, and is freed by FreeQueryDesc().
What the pointers refer to is owned by the extensions.

There are no users of this facility yet.  A follow-up commit will make
use of it.  Some potential use cases have been identified for
pg_stat_statements and auto_explain, where both need to be able to
co-exist in peace.  Extensions living outside of core may also find a
use for it.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Sami Imseih <samimseih.pg@gmail.com>
Discussion: https://postgr.es/m/CAEcQ1bZrgwKsauC=03otebkLk77Zc_hYNjhTP3OUdpXs++u+BA@mail.gmail.com

7 days agoAvoid truncated or zero-padded copies of replaced files in backups
Michael Paquier [Tue, 27 Oct 2026 04:53:26 +0000 (13:53 +0900)]
Avoid truncated or zero-padded copies of replaced files in backups

Base backups call stat() on each file while scanning the data directory,
and later send exactly that many bytes.  If the file is replaced by for
example a concurrent rename(), the backup contains the new file
truncated or zero-padded to the size of the old one.  This is harmless
for relation files as WAL replay repairs them.  However, it causes harm
for non-relation files manipulated as temporary file renamed in place.

Here is a list of non-relation files that use a temporary file followed
by a final rename() (I may be missing some):
* postgresql.auto.conf
* pg_logical/replorigin_checkpoint (a damaged copy fails its CRC check
and prevents startup)
* pg_prewarm's autoprewarm.blocks
* pg_stash_advice.tsv.

When sending files that are not relation files, fstat() is called again
on the opened file and the refreshed stats are used for the tar header
and the backup manifest.  Since the rename
is atomic, the opened file is always complete.  Relation files keep using
the earlier stat, to avoid copying data that WAL replay would restore
anyway (because that's cheaper).

Back-patch down to v15.  v14 is going to be EOL soon, so I have decided
to leave it out of the picture (risk/reward thing).

Author: David Steele <david@pgbackrest.org>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Shihao Zhong <zhong950419@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqS_On-pLgcv6xjH8mvGhdcPmfWtythW3r8pYKUG+hsiuQ@mail.gmail.com
Backpatch-through: 15

7 days agoCount the last block of the validation scan in a concurrent index build
Michael Paquier [Tue, 27 Oct 2026 03:12:47 +0000 (12:12 +0900)]
Count the last block of the validation scan in a concurrent index build

heapam_index_validate_scan() reports PROGRESS_SCAN_BLOCKS_DONE as the
number of the block that the scan starts on, forgetting to count the
last block scanned.

Due to the last block not being counted, the number of blocks_done never
matched blocks_total.  This information could remain on the view for a
long time, depending on the waits done between the phases of CREATE
INDEX CONCURRENTLY or REINDEX CONCURRENTLY.

This is incorrect still purely cosmetic, so no backpatch is done.

Author: Manu <manuelreyesbravo@gmail.com>
Discussion: https://postgr.es/m/179303526069.2212386.7608335332316408826@gmail.com

8 days agoFix pg_iswcased() for some libc case mappings.
Jeff Davis [Mon, 26 Oct 2026 22:11:21 +0000 (15:11 -0700)]
Fix pg_iswcased() for some libc case mappings.

Some C libraries, such as macOS libc, case-map characters that they do
not classify as upper or lower.  ILIKE index scans could then miss
rows, because those characters stayed in the fixed prefix.

Introduced in 630706ced0. 43a948b7b25 fixed similar issues, but missed
this one.

Author: shihao zhong <zhong950419@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqS6pr-hG-g=K6RTdRw53SnMZWz3iXvh_wi8rqLSf972sA@mail.gmail.com
Backpatch-through: 19

8 days agoInitialize FOUND to false in PL/pgSQL event trigger functions.
Tom Lane [Mon, 26 Oct 2026 21:15:27 +0000 (17:15 -0400)]
Initialize FOUND to false in PL/pgSQL event trigger functions.

The documentation says that FOUND starts out false within each
PL/pgSQL function call.  plpgsql_exec_function() and
plpgsql_exec_trigger() do set it so, but plpgsql_exec_event_trigger()
did not, leaving it NULL until the first statement that sets it.

Fix this by initializing FOUND to false, as the other two entry points
do.  While at it, also set estate.err_text to "during function entry"
during this action and the subsequent instrumentation plugin call,
again to match the other two routines.

Back-patch to v19, but no further.  It seems unlikely that any user
code is depending on the current behavior, but just in case, let's
not touch the stable branches.

Author: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAM2+6=U_=hZmgs1v1JJ-XJk2bpbfqQPP9MNRDbp5RoEsOW8xsQ@mail.gmail.com
Backpatch-through: 19

8 days agossl: Don't disable SSL for all hosts when one SNI host fails to load
Daniel Gustafsson [Mon, 26 Oct 2026 20:33:22 +0000 (21:33 +0100)]
ssl: Don't disable SSL for all hosts when one SNI host fails to load

On Windows and in EXEC_BACKEND builds every backend reloads the SSL
configuration, with no previous one to fall back on.  If a single
pg_hosts.conf entry failed to load there, the whole configuration was
discarded and the backend ran without SSL for every host.  Fix by
keeping the failed entry without an SSL context in child processes
and failing the handshake only for connections selecting it.

Also document that SSL_passphrase_cmd_reload must be enabled on
Windows, like commit 0f4f45772c5 did for the GUC.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CAN4CZFM-Hn7-bdKC8=xwCQiE128Y1Xao+aft=Grq5QA9OkZ9Kw@mail.gmail.com
Backpatch-through: 19

8 days agodoc: Fix option name in --filter description for pg_restore
Daniel Gustafsson [Mon, 26 Oct 2026 18:49:38 +0000 (19:49 +0100)]
doc: Fix option name in --filter description for pg_restore

The description of the "index" filter keyword referred to the --index
option as --indexes, which is a typo.  Oversight in commit a5cf808be5.

Author: Taras Kloba <taras.kloba@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CAODqpgofaVQBZ73rmPoj83Y1-6gbGhLiBKHD=82b1wiNkoF-AQ@mail.gmail.com
Backpatch-through: 17

8 days agoFix PL/pgSQL's handling of anycompatiblemultirange.
Tom Lane [Mon, 26 Oct 2026 18:03:23 +0000 (14:03 -0400)]
Fix PL/pgSQL's handling of anycompatiblemultirange.

When validating a PL/pgSQL function with polymorphic arguments or
result type, we substitute a plausible concrete type for each
polymorphic type.  anycompatiblemultirange was missed in both places
that do this, when multiranges were added.  As a result, CREATE
FUNCTION with an anycompatiblemultirange argument failed with
"PL/pgSQL functions cannot accept type anycompatiblemultirange" when
check_function_bodies is on.

Also, a function returning anycompatiblemultirange was compiled by
the validator with an int4 result type, and since the function cache
key doesn't include the result type, a later call in the same session
with int4range arguments reused that entry and failed trying to cast
the multirange result to integer.

Map anycompatiblemultirange to int4multirange, as is done for
anymultirange, to fix both issues.

Author: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAM2+6=VEXCo7tPaxX+9_zN8SJ9DiPp2NTj_sPGN+Tb0wWTBp=w@mail.gmail.com
Backpatch-through: 14

8 days agoAvoid waiting for a safe snapshot in notify-reading transactions.
Tom Lane [Mon, 26 Oct 2026 17:01:59 +0000 (13:01 -0400)]
Avoid waiting for a safe snapshot in notify-reading transactions.

In the perhaps-unlikely scenario where your session default settings
specify read-only, deferrable, serializable transactions, the implicit
transaction created by ProcessIncomingNotify() honored those settings
and would wait for a safe snapshot to be creatable; thereby getting
blocked by any long-running concurrent transaction.  This is a bit
surprising, especially if you think you are committing a transaction
that doesn't have those properties.

There doesn't seem to be any good semantic reason for NOTIFY reporting
to wait for a safe snapshot, so create a code pathway that lets it
just get a plain snapshot, independently of transaction mode.

Given the lack of field complaints about such issues, I don't feel a
need to back-patch this.

Author: shihao zhong <zhong950419@gmail.com>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAGRkXqQ1bmVwBw2CXiyZeWWP=XkHPXLPcQ7BSg2Q5JKSvDAnTA@mail.gmail.com

8 days agoFix pg_basebackup long-path test on Windows
Daniel Gustafsson [Mon, 26 Oct 2026 14:15:07 +0000 (15:15 +0100)]
Fix pg_basebackup long-path test on Windows

Create the long tablespace directory through the short side of the
Windows junction.  Also check mkdir and report its underlying error
instead of failing later with a misleading misleading error for
CREATE TABLESPACE.

Author: Harrison Booth <harrisontbooth@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CAAH-eSV4BJS7W=qRf7=Hk09XD3NhFOVvvKRjH+Lh0v9e_S=Seg@mail.gmail.com

8 days agoFix nbtree multi-level page deletion WAL record bug.
Peter Geoghegan [Mon, 26 Oct 2026 13:50:58 +0000 (09:50 -0400)]
Fix nbtree multi-level page deletion WAL record bug.

The second phase of a multi-level nbtree page deletion operation marks a
"top parent" internal page fully deleted, and updates the to-be-deleted
subtree's half-dead page.  The leaf page needs to have its top parent
link updated in preparation for marking the next top parent page (the
subtree page one level down) fully deleted.  The second phase reads the
leaf page's sibling links and releases its lock on the leaf, relocking
it only after it has examined the target page.  This created a small
window where stale information could be WAL logged.

It was just about possible for a concurrent split of the half-dead
page's left sibling page to update the half-dead page's left sibling
link.  _bt_unlink_halfdead_page neglected to re-copy the leaf page's
sibling links when it reacquired a lock on that page.  The atomic action
that the WAL record represents doesn't really need to change any of its
sibling links, so this shouldn't have been a problem.  However, since we
use REGBUF_WILL_INIT for the half-dead leaf page's buffer, using a stale
value led to corrupted half-dead leaf pages on standbys.  This bug has
been shown to cause wal_consistency_checking failures.

To fix, re-read btpo_prev (and btpo_next) from the leaf once it has been
relocked, before the links are logged.  That way we'll reliably WAL log
the current leafleftsib.

In practice this bug was very hard to hit.  It required a concurrent
split at just the right/wrong time, with a multi-level page deletion.
Even then, the resulting corruption on standbys only persisted until the
half-dead page was marked fully deleted -- which typically happened
immediately after the corruption was introduced.

Oversight in commit efada2b8e9, which fixed a race condition in nbtree
page deletion.

Author: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-Wznr2Gw5OQE9KMP_Xd92F9mV=gv7qE9Q6taAvfrKqsE5Qg@mail.gmail.com
Backpatch-through: 14

8 days agopg_combinebackup: Reject out-of-range block numbers in incremental files
Peter Eisentraut [Mon, 26 Oct 2026 09:22:02 +0000 (10:22 +0100)]
pg_combinebackup: Reject out-of-range block numbers in incremental files

The header of an incremental file was only partially validated:
num_blocks and truncation_block_length were checked against
RELSEG_SIZE, but the block numbers stored after them were not checked
at all.  A block number of 0xFFFFFFFF made
find_reconstructed_block_length() compute a reconstructed length of
zero, since it adds 1 to the block number in 32-bit arithmetic, and
reconstruct_from_incremental_file() then allocated zero-length
sourcemap and offsetmap arrays but still indexed them with the block
numbers taken from the file.  In an assertions-enabled build, this
would be caught by an Assert, but otherwise it would index the arrays
out of bounds, typically crashing the process.

To fix, check the block numbers when the header is read, like the
other header fields.

Reported-by: Sajeeb Lohani working with TrendAI Zero Day Initiative
8 days agoFix partial two-phase files left by crash during checkpoint
Michael Paquier [Mon, 26 Oct 2026 08:14:07 +0000 (17:14 +0900)]
Fix partial two-phase files left by crash during checkpoint

CheckPointTwoPhase() wrote each 2PC file in place, with O_TRUNC.  A
crash mid-write, or a base backup copying the file at that point left an
empty or partial file that would make startup fail, most likely on an
"incorrect size of file" ERROR.

The 2PC files are now written through a temporary file that gets renamed
at the end, relying on the atomicity of the rename to make startup safe,
be it after a crash or a base backup.

Author: Shihao Zhong <zhong950419@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: David Steele <david@pgbackrest.org>
Discussion: https://postgr.es/m/CAGRkXqS_On-pLgcv6xjH8mvGhdcPmfWtythW3r8pYKUG+hsiuQ@mail.gmail.com
Backpatch-through: 14

9 days agoDon't build child-join EC members that reference outside rels
Richard Guo [Mon, 26 Oct 2026 02:32:04 +0000 (11:32 +0900)]
Don't build child-join EC members that reference outside rels

add_child_join_rel_equivalences() built a child version of every
multi-relation EquivalenceClass member that overlapped the child
join's topmost parent relids.  For a member that also references a
relation outside the join, the child version is of no use for what
these members exist for, which is matching sort pathkeys of the child
join, since such a member cannot be computed there.

The only effect of these members was on the clauses generated for
parameterized child-join paths, and it was a harmful one.  Each child
join nested within a larger child join supplies its own version of
such a member, as does each rebuild of the same child join by GEQO.
These versions are all the same expression, yet
generate_join_implied_equalities() would equate them to each other,
producing redundant clauses that share one rinfo_serial and so trip
the assertion added by commit 8510bcc98.  Even a lone such member
could yield a join clause that duplicates a condition already enforced
by the inner path, as seen in an existing regression test whose plan
now loses a redundant join filter.

To fix, consider only members that can be computed at the child join's
topmost parent joinrel.  This matches what add_child_rel_equivalences()
has done for base relations since commit 2489d76c4.

In passing, simplify how both functions compute the child member's
relids.  Now that the parent member's relids are known to lie within
the parent rel, the child member's relids are simply the child rel's.

Back-patch to v19, as with commit 8510bcc98.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/4a0d7906-14f4-4992-8815-16e17e1f6655@gmail.com
Backpatch-through: 19

9 days agoLook through wrapper paths when collecting enforced clause serials.
Richard Guo [Mon, 26 Oct 2026 01:02:54 +0000 (10:02 +0900)]
Look through wrapper paths when collecting enforced clause serials.

get_param_path_clause_serials() handles join paths and Append paths
explicitly, and for anything else returns the ppi_serials of the
path's ParamPathInfo on the assumption that it is a baserel scan.  But
Material, Memoize, Projection, Sort, IncrementalSort, Unique, Agg and
GroupingSets paths all inherit their subpath's ParamPathInfo, and that
assumption fails when the subpath is a join or Append.

This could drop a join clause for good.  If a LATERAL UNION ALL
subquery references an outer relation in an expression that becomes an
EquivalenceClass member, the members get no child version of it, so
their parameterized scans cannot enforce the derived clause.  The
appendrel's ParamPathInfo claims it nonetheless, and once a
Materialize sat on the Append, create_nestloop_path() dropped the
clause from the join above as already enforced, returning rows that
fail it.

To fix, make get_param_path_clause_serials() recurse through such
wrapper paths, since they enforce no clauses of their own.  Also use
it in get_memoize_path(), which unsafely read ppi_serials directly for
its inner-unique check.

To try to clarify what's going on here, introduce a new function
get_wrapper_parampathinfo() that pathnode.c should use instead of
directly assuming that copying a wrapper path's subpath's param_info
is what to do.  This is just cosmetic at present but might become
less so in future.

Back-patch to v16, where the serial-based detection of enforced
clauses was introduced.

Author: Richard Guo <guofenglinux@gmail.com>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: shihao zhong <zhong950419@gmail.com>
Reviewed-by: Matheus Alcantara <matheusssilv97@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49jVFRZ7oOgMK9zYt7d=SLxpiz=dN=QMu5iV8TS+9T0AA@mail.gmail.com
Backpatch-through: 16