postgresql.git
29 hours agodoc: fix wording in SELECT docs
Bruce Momjian [Fri, 21 Aug 2026 01:35:26 +0000 (21:35 -0400)]
doc:  fix wording in SELECT docs

Reported-by: Garry Polley
Author: Garry Polley

Discussion: https://postgr.es/m/CAPj_C4wRh_JSi_RSFZLPUDVoVeOjFhos5RG+DggtK38wzakjEQ@mail.gmail.com

Backpatch-through: master

30 hours agoAttempt to stabilize plan of self-join test in tidscan.sql
David Rowley [Fri, 21 Aug 2026 00:25:46 +0000 (12:25 +1200)]
Attempt to stabilize plan of self-join test in tidscan.sql

The test that checks the expected plan for this self-join test has been
known to have failed in the past due to badly timed VACUUMs causing
small variations in row estimates on one of the tables, resulting in a
swapped join order.  Currently, failures have only been seen in v14, and
seemingly due to 74388a1ac and 4496020e6 the failures have not been seen
in more recent versions.

Here we shrink down the number of matching rows on one side of the join
to make the alternative join order's costs more expensive relative to
the cheapest join order.  Previously the alternative order had the same
cost.

We do this in all supported versions to reduce the chances of future
changes reintroducing stability issues with these queries.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/f5d1f4c2-6224-4797-be17-c86e77f96c9c@gmail.com
Backpatch-through: 14

30 hours agoFix snapshot import xmin ProcArrayLock bug.
Peter Geoghegan [Thu, 20 Aug 2026 23:47:32 +0000 (19:47 -0400)]
Fix snapshot import xmin ProcArrayLock bug.

ProcArrayInstallImportedXmin verifies that the source transaction (the
transaction whose snapshot we're importing) is still running, and then
installs the caller's imported xmin.  These steps have to be atomic.
But it was just about possible for VACUUM to fail to observe the
imported xmin in either the source proc or the importing one.  This
could result in VACUUM pruning away deleted tuples that were still
visible to the imported snapshot.

To fix, take ProcArrayLock in exclusive mode while importing an exported
snapshot's xmin within ProcArrayInstallImportedXmin.  That guarantees
that a concurrent VACUUM's OldestXmin cannot advance past the xmin (one
proc or the other always advertises an xmin that holds it back).

Author: Chee Wooson <chee.wooson@gmail.com>
Reviewed-by: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/20260730042128.714201-1-chee.wooson@gmail.com
Backpatch-through: 14

31 hours agoecpg: Add missing NULL check in ecpg_store_input() following OOM failure
Michael Paquier [Thu, 20 Aug 2026 23:28:07 +0000 (08:28 +0900)]
ecpg: Add missing NULL check in ecpg_store_input() following OOM failure

ecpg_store_input() called strlen() directly on the result of
PGTYPESnumeric_to_asc() without checking for a NULL value, state
possible when the function fails due to an out-of-memory failure.

This error is unlikely going to be hit in practice, so no backpatch is
done.

Author: Gladyshev Ilya <ilya.gladyshev@linux.dev>
Discussion: https://postgr.es/m/ed5a633b469e685f3a1aef9982cff8e1c50e5883@linux.dev

31 hours agoImprove error for RETURNING with system columns under rules
Michael Paquier [Thu, 20 Aug 2026 22:51:16 +0000 (07:51 +0900)]
Improve error for RETURNING with system columns under rules

When a DML query's RETURNING list references the system column of a
target table, and the query was rewritten by a rule with its own
RETURNING clause, ReplaceVarsFromTargetList() failed with an internal
error "could not find replacement targetlist entry for attno -1",
since the rule's RETURNING list only has entries for user columns.

Such queries cannot work: the rewritten query need not scan the original
target relation at all, so a rule's RETURNING list has no way to provide
values for that relation's system columns.

This is a life improvement change as the error reported is just more
relevant for the user and this has never worked since RETURNING is
reported.  No backpatch is done, based on the lack of complaints over
the ages.

Reported-by: Zheng Wang <hackerzheng666@gmail.com>
Author: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/19632-9155d9baec763c8c@postgresql.org

32 hours agotest_aio: Fix broken error recovery assertions in 001_aio
Michael Paquier [Thu, 20 Aug 2026 22:05:08 +0000 (07:05 +0900)]
test_aio: Fix broken error recovery assertions in 001_aio

The three error recovery checks in `test_handle()` used "qr/^|ok$/" to
look for the marker "ok" in psql's output.  '^' matches every string, so
the assertions passed no matter what psql printed.

Spelling the regex correctly as "qr/^ok\|$/" exposed that the explicit
xact case was actually failing, reporting an incorrect "current
transaction is aborted" instead of showing that an AIO handle can be
acquired again after an error.  This is rewritten with a ROLLBACK,
similarly to the subxact counterpart.

While on it, the subxact case had no marker column in its query, so add
one there for consistency, and reformat to use same pattern.

Author: Jelte Fennema-Nio <me@jeltef.nl>
Discussion: https://postgr.es/m/DKSU6GI1YLG5.3VF6M4IRKQ7XE@jeltef.nl
Backpatch-through: 18

33 hours agohashtext: fix fragile code.
Jeff Davis [Thu, 20 Aug 2026 20:54:56 +0000 (13:54 -0700)]
hashtext: fix fragile code.

Previously, in the path for non-deterministic collations, the code
assumed that bsize==rsize. That assumption seems to be true for ICU,
and all non-deterministic collations are ICU, so it's not known to be
an actual bug.

The only known place where bsize may not equal rsize is in the libc
provider, where strxfrm() can return an upper bound of the size needed
to store the result. That means the initial call to determine the
buffer size (with dest==NULL, n==0) could return a larger number than
the actual call with an adequate dest buffer. That's OK, because libc
locales are always deterministic.

Commit 679c5084cf2 partially fixed the assumption, but missed this
part. Fix it, and add a more prominent documentation note.

Reviewed-by: Haibo Yan <tristan.yim@gmail.com>
Discussion: https://postgr.es/m/CABXr29Hb31nkj1g2Jmk+1BhAm=3ecGs_pWy4tU++j8CQBnbMxQ@mail.gmail.com
Backpatch-through: 16

33 hours agoSimplify autovacuum's TOAST-to-main-relation reloptions map.
Nathan Bossart [Thu, 20 Aug 2026 20:56:19 +0000 (15:56 -0500)]
Simplify autovacuum's TOAST-to-main-relation reloptions map.

The ar_relid and ar_hasrelopts members of the av_relation struct
can be removed.  ar_relid isn't used by anything, and we only need
ar_hasrelopts because we add an entry to the map even when the main
table has no reloptions set.  If we instead only add entries for
tables with reloptions set, we can take the presence of an entry to
mean the main table has some.

Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Tested-by: Greg Burd <greg@burd.me>
Tested-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/aFRxC1W_kZU9OjJ9%40nathan

35 hours agodoc: change "allowed in->on the standby server."
Bruce Momjian [Thu, 20 Aug 2026 19:32:55 +0000 (15:32 -0400)]
doc:  change "allowed in->on the standby server."

Reported-by: phamnguyenducduong@gmail.com
Backpatch-through: master

37 hours agoMicro-optimize appendStringInfo[VA].
Tom Lane [Thu, 20 Aug 2026 17:01:28 +0000 (13:01 -0400)]
Micro-optimize appendStringInfo[VA].

In the loop in appendStringInfo, avoid a useless assignment to
errno during the first (and usually only) iteration.  This
might make a noticeable difference depending on how efficiently
the platform deals with thread-local variables.

Try to make the compiler inline appendStringInfoVA into
appendStringInfo.

Instead of having appendStringInfoVA go through pvsnprintf, make
it call vsnprintf directly.  pvsnprintf adds little except an
int-versus-size_t impedance mismatch.  We do have to duplicate its
error handling for the nprinted < 0 case, but we don't need to
duplicate its check for MaxAllocSize overrun, because
enlargeStringInfo can handle that just as easily.  Also, its
insistence on adding one to nprinted is not needed here, since
enlargeStringInfo expects the number of data bytes to add.

In combination, these changes seem to about halve the penalty for
going through appendStringInfo rather than directly to snprintf.c.
This is enough to buy back the performance loss incurred in
formatting.c by the preceding three patches, and even a little more.
It should help other usages too.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/3451175.1786641871@sss.pgh.pa.us

37 hours agoReplace formatting.c's fixed-size output buffers with StringInfos.
Tom Lane [Thu, 20 Aug 2026 16:57:25 +0000 (12:57 -0400)]
Replace formatting.c's fixed-size output buffers with StringInfos.

In both versions of NUM_processor(), use a StringInfo for the
output string, eliminating the need to guess an upper bound
for the output length, and removing the need to truncate some
strings of unpredictable length.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/3451175.1786641871@sss.pgh.pa.us

37 hours agoRestructure formatting.c's NUM_processor() to add some const-sanity.
Tom Lane [Thu, 20 Aug 2026 16:55:13 +0000 (12:55 -0400)]
Restructure formatting.c's NUM_processor() to add some const-sanity.

NUM_processor() is an under-documented mess.  Depending on the value
of is_to_char, it either reads "inout" and writes "number", or
the other way around.  That makes it impossible to label either
string "const", which seems like a minimum expectation in 2026.
It also complicates replacing the output buffer with a StringInfo:
we'd have to convert both strings, which is pretty pointless for
the input side.

Moreover, we're buying very little code savings by doing it like this,
since a large majority of the function's code has to be wrapped inside
"if (is_to_char)" tests.

To fix, split the function into NUM_processor_from_char() and
NUM_processor_to_char(), and rename/const-ify arguments as
appropriate.  Both paths now read from "const char *input"
and write to "char *output".

This patch doesn't intend to make any algorithmic changes, it's
just mechanical code rearrangement and symbol renaming.  The
only real exception is that I got rid of passing "input_len"
to NUM_processor_from_char()'s subroutines in favor of storing
"const char *input_end" in NUMProc.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/3451175.1786641871@sss.pgh.pa.us

37 hours agoConvert DCH_to_char() to use a StringInfo as destination.
Tom Lane [Thu, 20 Aug 2026 16:52:06 +0000 (12:52 -0400)]
Convert DCH_to_char() to use a StringInfo as destination.

Formerly, we allocated an output char array with 12 bytes per
byte of the format string.  That's usually far more than enough,
and yet we had to add assorted code to defend against cases where
it isn't enough.  Switch to using a StringInfo expansible buffer
instead.  This is considerably more robust, shortens the code
noticeably, and eliminates various edge-case failure conditions.

While at it, const-ify some parameters that can be const.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/3451175.1786641871@sss.pgh.pa.us

38 hours agoEnsure all pg_locale.h APIs work with collate_is_c.
Jeff Davis [Thu, 20 Aug 2026 16:25:34 +0000 (09:25 -0700)]
Ensure all pg_locale.h APIs work with collate_is_c.

Safer for callers, so that checking collate_is_c is only needed if the
caller wants to optimize for that case.

Backpatch to avoid creating a hazard for other backpatches in this
area.

Suggested-by: Andres Freund <andres@anarazel.de>
Suggested-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/v36ssaygf7grb3qzfsjhtdzi7kqd45ds56nyuf7gi5qjml4qbb@ezmfqzmhlrs2
Backpatch-through: 18

39 hours agoRewrite tsqueryout() to use StringInfo to build the output string.
Tom Lane [Thu, 20 Aug 2026 15:36:17 +0000 (11:36 -0400)]
Rewrite tsqueryout() to use StringInfo to build the output string.

This patch started with noticing that tsquery.c's infix() function
uselessly multiplies the length of each operand string by
pg_database_encoding_max_length() + 1, where multiplying by 2
would be sufficient.  Unlike the related thinko in tsvectorout(),
this doesn't seem to risk integer overflow, since we're multiplying
only a rather short per-operand length.  Still, it's incorrect and
misleading.

However, I then started to question why tsqueryout() is using a
hand-rolled implementation of an expansible string buffer in the
first place.  Replacing that by using the StringInfo infrastructure
would make the code noticeably shorter and eliminate not only this
mistake but a bunch of other mistake-prone arithmetic.  It might
even be faster, given that we've spent effort on micro-optimizing
StringInfos; but even if it's slower, it's hard to visualize a
workload where tsqueryout() is a performance bottleneck.  So
that's what this patch does.

I also got rid of the overly-creative approach of deparsing a
binary operator's right operand into a separate buffer, then
deparsing the left operand into the main output buffer, then
copying the right operand's text back to the main buffer.
(Why the operands are stored in reverse order in the first place
seems lost in the mists of time, but I suppose we're stuck with
that choice.)  We can easily emit the desired text in-order by
moving the "curpol" next-item pointer around.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/3428771.1786635967@sss.pgh.pa.us

39 hours agoRemove redundant SvOK() tests in plperl.
Tom Lane [Thu, 20 Aug 2026 15:26:11 +0000 (11:26 -0400)]
Remove redundant SvOK() tests in plperl.

I noticed that some places in our code test "SvOK(sv) && SvROK(sv)"
while others check just SvROK(sv).  On investigation, it's clear
that SvROK implies SvOK so testing both is pointless.  While removing
these extra checks seems very unlikely to make any performance
difference, it does make the code more consistent and intelligible.

Also mop up a couple of places where there wasn't a null-pointer
check before a SvOK() test.  I think these are unreachable cases,
but in the name of consistency let's do it the same everywhere.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Discussion: https://postgr.es/m/2034677.1787172042@sss.pgh.pa.us

45 hours agoSkip bogus find_composite_type_dependencies() call on sequences
Heikki Linnakangas [Thu, 20 Aug 2026 08:45:51 +0000 (11:45 +0300)]
Skip bogus find_composite_type_dependencies() call on sequences

A sequence has no rowtype.  We called
find_composite_type_dependencies() with InvalidOid, which is harmless
but pointless.  Skip it.

This started to happen with commit 344d62fb9a97 in v15, which added
the ALTER SEQUENCE ... SET LOGGED/UNLOGGED subcommand.  Before that,
sequences were never rewritten.  While this is harmless, backpatch to
keep the code the same on all branches, to make backpatching future
patches a little easier.

Backpatch-through: 15

46 hours agoTrack RI fast-path FK-check batches per firing cycle
Amit Langote [Thu, 20 Aug 2026 08:12:39 +0000 (17:12 +0900)]
Track RI fast-path FK-check batches per firing cycle

Commit 34a30786293 fixed an RI fast-path crash under nested C-level SPI
by keeping batch-callback lists per after-trigger query depth.  That fix
was incomplete: the RI fast path still tracked callback registration
with one global flag.  Once an outer firing cycle had registered its
callback, the flag suppressed registration for a nested cycle, leaving
the nested batch to be handled by the outer callback, too late and with
the wrong snapshot, potentially after the ResourceOwner holding its
relations had gone away.

Nor is per-depth callback registration sufficient while the cache is
keyed only by constraint OID.  If nested firing checks the same
constraint, it reuses the outer entry, combining rows that must be
checked in separate firing cycles.

Key the cache by both constraint OID and query depth.  Register a callback
for each depth that creates an entry, and make ri_FastPathEndBatch() flush
and release only entries belonging to the ending depth.  Add
AfterTriggerCurrentQueryDepth() so ri_triggers.c can obtain the current
depth; depth -1 represents deferred firing.

Add regression coverage for nested firing through a cursor portal, whose
resources must not outlive the nested cycle, nested firing of the same
constraint at different query depths, and deferred firing at query depth
-1.

Reported-by: Noah Misch <noah@leadboat.com>
Reported-by: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/20260705222115.be.noahmisch@microsoft.com
Discussion: https://postgr.es/m/CAH2-Wz=D533JbF_ak_Pc8kP0FKse-ju8DnMxtjvY==yHsP4xgw@mail.gmail.com
Backpatch-through: 19

47 hours agoUnify error messages
Peter Eisentraut [Thu, 20 Aug 2026 06:53:57 +0000 (08:53 +0200)]
Unify error messages

and some small style improvements

2 days agoFix postmaster failing to exit when startup crashes during crash restart
Michael Paquier [Thu, 20 Aug 2026 06:17:26 +0000 (15:17 +0900)]
Fix postmaster failing to exit when startup crashes during crash restart

Commit 9b43e6793b0f removed the PM_STARTUP shortcut that exited the
postmaster directly when the startup process died, routing the case
through HandleChildCrash() so that children processes running during
PM_STARTUP are cleaned up rather than orphaned.

However, HandleChildCrash() does nothing if FatalError is already set,
and that is exactly the case while reinitializing after a crash: a
relaunched startup process that dies before WAL redo starts would leave
the state machine stuck at PM_STARTUP, preventing the postmaster to shut
down.

This issue is fixed by restoring the pre-9b43e6793b0f shortcut behavior:
if FatalError is set when the startup process crashes, signal the
remaining children and move to PM_NO_CHILDREN, so as the postmaster can
properly exit with nothing orphaned.  This is only reachable in v18 and
newer versions, the early return of HandleChildCrash() on FatalError
being introduced in f0b7ab725139.

This issue has been reported on Windows, for a postmaster with its
console gone.  A trick to make InitPostmasterChild() fail aggressively
was equally able to stuck a postmaster.

Reported-by: Kuan-Ting Kuo <m0935388420@gmail.com>
Author: Zexin Li <lizi.openmind@gmail.com>
Discussion: https://postgr.es/m/19623-f9bd331940be1273@postgresql.org
Backpatch-through: 18

2 days agoRestore after-trigger firing context at subtransaction end
Amit Langote [Thu, 20 Aug 2026 05:02:51 +0000 (14:02 +0900)]
Restore after-trigger firing context at subtransaction end

AfterTriggerEndQuery(), AfterTriggerFireDeferred(), and
AfterTriggerSetState() bracket their firing loops with
firing_depth++/--.  The decrement runs after the loop and is not
protected by PG_FINALLY, so an error caught by a subtransaction (e.g. a
PL/pgSQL EXCEPTION block) leaves firing_depth too high.  Separately,
AfterTriggerEndSubXact() unconditionally cleared
firing_batch_callbacks, even if the subtransaction began while an outer
batch-callback loop was active.

firing_depth feeds AfterTriggerIsActive(), which the RI fast path uses
to decide whether an FK check is running inside trigger firing and may
batch.  A stranded firing_depth makes AfterTriggerIsActive() wrongly
report firing as active afterwards.  This is reachable and results in
silent data corruption: after a caught FK-check error, an ALTER TABLE ...
ADD FOREIGN KEY whose validation runs per-row (RI_Initial_Check() having
bailed, e.g. because RLS is enabled on the referenced table) calls
RI_FKey_check() with AfterTriggerIsActive() wrongly true.  The check is
routed into the batched fast path, but a utility command has no
AfterTriggerEndQuery() to fire the flush callback.  The violating row is
not reported, the constraint is marked validated, and the cached PK
relation and index leak.

Save firing_depth and firing_batch_callbacks at subtransaction start and
restore them in AfterTriggerEndSubXact(), next to the existing query_depth
handling.  Restoring, rather than zeroing or clearing, is required because
a subtransaction can begin and end while an outer query is firing, where
firing_depth is legitimately positive and firing_batch_callbacks may be
legitimately set.

Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/20260705222115.be.noahmisch@microsoft.com
Backpatch-through: 19

2 days agoReject too many arguments in CREATE TRIGGER
Michael Paquier [Thu, 20 Aug 2026 00:38:23 +0000 (09:38 +0900)]
Reject too many arguments in CREATE TRIGGER

The number of trigger arguments is stored as a smallint, but there was
no check that the number of arguments fits with the catalog data type.
This could result in an invalid negative value being stored once one
defined more than INT16_MAX arguments, with an overflowed value stored
in the catalogs.

Looking at other catalogs that store a number of arguments, we have
similar protections already in place (aggregates, functions, etc.).

Reported-by: Xingwang Xiang <v3rdant.xiang@gmail.com>
Author: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://postgr.es/m/19627-5b72a57e332e2b3f@postgresql.org
Backpatch-through: 14

2 days agoGiST: Invalidate killed items consistently.
Peter Geoghegan [Wed, 19 Aug 2026 19:45:56 +0000 (15:45 -0400)]
GiST: Invalidate killed items consistently.

GiST neglected to invalidate its killedItems[] array on a rescan.  As a
result, it was just about possible for the wrong tuples from the wrong
index page to be LP_DEAD-marked on a rescan.  The scan mistakenly
believed that the previous rescan's killedItems[] were for this rescan's
curBlkno, causing index corruption.

To fix, bring GiST in line with nbtree and hash: call gistkillitems from
both gistrescan and gistendscan (the existing gistgettuple caller still
handles the common case where we need to LP_DEAD-mark before moving on
to the next page).  That way the scan's pending killedItems[] are passed
to gistkillitems while they still describe items from curBlkno.  When
gistkillitems runs, it'll invalidate the array in passing (and won't
needlessly miss out on an opportunity to LP_DEAD-mark eligible index
tuples).  Back branches just get minimal hardening: we invalidate
killedItems[] at the places where the master branch gets new calls to
gistkillitems (and we invalidate curBlkno and curPageLSN on a rescan).

The test that proved corruption on master didn't result in corruption on
any stable branch, though only because, without commit 9c9ddf109, we'd
clobber curPageLSN without also updating curBlkno -- which accidentally
prevented it.  Relying on gistkillitems to not LP_DEAD-mark by passing
it a curBlkno whose curPageLSN was taken from an entirely different page
seems like a very bad idea, which is why this issue is being treated as
a bug affecting all stable branches.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-By: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-WzmwEThnQf17Ju+t0N9_KJLsEQSXzYrFnaS2=s4KnGGrqw@mail.gmail.com
Backpatch-through: 14

2 days agoSupport tied Perl objects in plperl and associated contrib modules.
Tom Lane [Wed, 19 Aug 2026 18:06:52 +0000 (14:06 -0400)]
Support tied Perl objects in plperl and associated contrib modules.

Up to now, if you passed a "tied" object to a PL/Perl operation,
it would most likely get treated as "undef", since we failed to
perform get magic on values we're passed.  Tied hashes worked
partially, in that you could read out their keys, but the values
always read as undef.

To fix, use hv_iterval() not HeVAL() to fetch values from perl
hashes, and be careful to apply plperl_materialize_sv() before
testing SvOK() or SvROK() on any perl SV.

Add regression test cases exercising some typical usage scenarios
for tied objects.

Arguably this is a bug fix, but in view of the lack of field
complaints to date, let's treat it as a new feature instead.
The risk/reward ratio for back-patching isn't attractive.

Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/569769.1786901901@sss.pgh.pa.us

2 days agoFix GIN multiple-VACUUM-scans pending list bug.
Peter Geoghegan [Wed, 19 Aug 2026 17:46:45 +0000 (13:46 -0400)]
Fix GIN multiple-VACUUM-scans pending list bug.

ginbulkdelete performs pending list cleanup before it searches the entry
tree (and any posting trees) for dead TIDs.  This is necessary to avoid
leaving behind dangling TID references that index vacuuming is required
to remove; nothing prevents recently inserted pending list tuples from
containing TIDs that VACUUM already considers dead.

However, ginbulkdelete neglected to perform pending list cleanup on
VACUUM's second or subsequent call.  It was therefore possible for a
VACUUM that requires multiple rounds of index vacuuming to leave behind
dangling references.

To fix, teach ginbulkdelete to perform pending list cleanup during every
call.  In passing, tweak some related comments in the pending list
cleanup path to make it clear why it's safe for VACUUM to not _fully_
empty an index's pending list.

This was arguably an oversight in commit e2c79e14, which fixed a similar
issue where pending list cleanup by VACUUM could end early, but missed
this closely related problem.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-Wzmsa-RPA2Ko8A5LaGOnmbpimJ--71xkiBqwgjk3Fq8YEg@mail.gmail.com
Backpatch-through: 14

2 days agoFix GIN VACUUM posting tree root split bug.
Peter Geoghegan [Wed, 19 Aug 2026 16:31:09 +0000 (12:31 -0400)]
Fix GIN VACUUM posting tree root split bug.

ginVacuumPostingTreeLeaves swaps a shared buffer lock for an exclusive
one when it encounters a leaf page.  It neglected to re-verify whether a
page that was initially a leaf root page became an internal page due to
a concurrent root page split (during the window when no lock was held).
It was therefore possible for GIN VACUUM to spuriously treat an internal
page as a leaf page, leading to data corruption.  VACUUM could miss dead
TIDs that it was required to remove, leaving behind dangling references
in the index.

To fix, re-verify that a leaf page is still a leaf page after an
exclusive lock is acquired.  If it isn't, drop our exclusive lock and
acquire a shared lock so that the non-leaf root page gets processed in
the usual way.

Oversight in commit fd83c83d, which fixed a deadlock bug in GIN posting
tree vacuuming.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-Wz=RBpJTQgvOxr6C=J04dExmFSt1E3F-r+cRTQ56hEotkg@mail.gmail.com
Backpatch-through: 14

2 days agoFix compilation warning in 0ee83dd4a994
Alexander Korotkov [Wed, 19 Aug 2026 14:30:48 +0000 (17:30 +0300)]
Fix compilation warning in 0ee83dd4a994

Discussion: https://postgr.es/m/CAO6_XqrGH2NRe0oFx_00nLXra1UZezd3jbS9pgoRhZtgzHD9gg%40mail.gmail.com
Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Reviewed-by: Alexander Pyhalov <a.pyhalov@postgrespro.ru>
2 days agopostgres_fdw: push down FUNCTION RTE into foreign joins
Alexander Korotkov [Wed, 19 Aug 2026 10:29:47 +0000 (13:29 +0300)]
postgres_fdw: push down FUNCTION RTE into foreign joins

A foreign join planning hook now considers a (foreign-table x function-RTE)
INNER join as a push-down candidate when the function expression is
IMMUTABLE and otherwise shippable.  The remote query absorbs the function
call as a FROM-list item (e.g. unnest(...) AS f<rti>(c1, c2, ...)), so the
foreign side returns only rows that match the function-produced set and the
join executes entirely on the remote.

An IMMUTABLE function gives the same result on any server, so the same
function RTE can be a push-down candidate for several distinct foreign
servers without semantic risk.  To keep the planner state consistent
across those independent attempts, the per-call stub fpinfo for the
function side lives on the joinrel's PgFdwRelationInfo (new
outer_func_fpinfo / inner_func_fpinfo), never on the function rel itself,
and the function side is detected via rtekind rather than fdw_private.

set_foreign_rel_properties() propagates fdwroutine onto a joinrel that
pairs a foreign rel with an RTE_FUNCTION rel so GetForeignJoinPaths gets
called; the FDW retains full control over whether to actually generate a
path.  deparseRangeTblRef and deparseColumnRef gain a FUNCTION-RTE branch
that emits the function expression and resolves Vars to the generated
column aliases.

Discussion: https://postgr.es/m/e3af56f9b2f1bd9fdf12aff6ca25b18d%40postgrespro.ru
Author: Alexander Pyhalov <a.pyhalov@postgrespro.ru>
Reviewed-by: Solaimurugan Vellaipandiyan <drsolaimurugan.v@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
2 days agoTighten ACL check in repack_is_permitted_for_relation()
Álvaro Herrera [Wed, 19 Aug 2026 10:25:06 +0000 (12:25 +0200)]
Tighten ACL check in repack_is_permitted_for_relation()

repack_is_permitted_for_relation() uses pg_class_aclcheck_ext()
to silently skip a concurrently-dropped relation.  That's wrong
for a caller that may already hold a lock on the relation whose
ACL is checked, where missing a relation is not fine, and it
makes the single-relation REPACK and CLUSTER cases more brittle.
So only detect a missing relation where that's expected,
following the fix for vacuum_is_permitted_for_relation() in
commit 824d5f6241ea.

The new already_locked behavior is limited to get_tables_to_repack()
and get_tables_to_repack_partitioned().  All other callers of
repack_is_permitted_for_relation() hold a lock on the relation
that prevents it from being concurrently dropped, so this commit
also adds an assertion to that effect.

While at it, update the comment in RangeVarCallbackMaintainsTable to
also mention REPACK.

Author: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Backpatch-through: 19
Discussion: https://www.postgresql.org/message-id/CALj2ACX3pyuRS8%2B%2B6L20cJUMRTf_qbbVp69J1btJ3y6%3D77e5gw%40mail.gmail.com

2 days agoGive RI fast-path cached FmgrInfos their own memory context
Amit Langote [Wed, 19 Aug 2026 07:10:18 +0000 (16:10 +0900)]
Give RI fast-path cached FmgrInfos their own memory context

ri_populate_fastpath_metadata() copies the cast and equality FmgrInfos
into the cached FastPathMeta with fn_mcxt set to TopMemoryContext, the
context active at the copy.  fn_mcxt is scratch space for the called
function: record_eq(), and the record I/O functions generally, allocate
their per-call cache there and keep a pointer to it in fn_extra.

Because that scratch is in TopMemoryContext, it outlives the metadata.
When the metadata is discarded on invalidation, whatever the cast and
equality functions cached is left behind, with nothing pointing at it.
Each subsequent repopulation allocates afresh, so a session that
repeatedly invalidates a foreign key constraint grows TopMemoryContext
without bound.

Give the metadata its own context for the FmgrInfos' fn_mcxt and delete
it along with the metadata, so the cached scratch is freed with the
FmgrInfos that point at it.  Since the preceding commit defers release
of the metadata to AtEOXact_RI(), the context is deleted there rather
than in InvalidateConstraintCacheCallBack().

The context deliberately is not reset while the metadata is in use.
fn_extra points into fn_mcxt, so resetting it would leave those
pointers dangling; the next call would find fn_extra non-NULL and read
freed memory.  fmgr_info_copy() zeroing fn_extra in the copy is the
same invariant seen from the other side.  Nothing accumulates in the
context during use in any case: record_eq() and friends allocate only
when fn_extra is NULL and reuse the cache afterwards.

Reported-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/20260705210533.ee.noahmisch@microsoft.com
Discussion: https://postgr.es/m/CA+HiwqFFB6vzx8v3t2=rbNYyxMistLf5kkJfqzJ81nadFyLrxA@mail.gmail.com
Backpatch-through: 19

2 days agoDon't free fast-path FK metadata from the inval callback
Amit Langote [Wed, 19 Aug 2026 07:06:00 +0000 (16:06 +0900)]
Don't free fast-path FK metadata from the inval callback

Commit e484b0eea6 made InvalidateConstraintCacheCallBack() pfree an
entry's FastPathMeta to plug a leak, but that breaks the rule stated
atop the callback: entries may have active references at invalidation
time, so we mark them invalid rather than removing them.

The metadata is subject to the same rule.  ri_FastPathCheck() and
ri_FastPathBatchFlush() copy riinfo->fpmeta into a local, and
ri_FastPathFlushArray() additionally takes FmgrInfo pointers into it
before its "walk all matches" loop.  That loop runs
index_getnext_slot(), ri_LockPKTuple(), and user-supplied cast and
equality functions, any of which can accept invalidation messages, and
a user function that performs DDL triggers one deliberately, no
concurrency required.  The callback then freed the object still in use,
so the loop read freed memory and called through FmgrInfos in it.

Fix by unlinking the metadata from the entry, so the next check
rebuilds it as before, but deferring the actual free to AtEOXact_RI(),
which runs from CommitTransaction() / PrepareTransaction() /
AbortTransaction() with no RI check on the stack.  Detached objects
are chained through a new next_dead field and released there.

The queue holds a few kB per detached object until the transaction
ends, which only affects transactions that interleave DDL with
FK-checking DML. That seems clearly preferable to a use-after-free.

Unlinking alone is not enough for the multi-column path.
ri_FastPathFlushLoop() calls build_index_scankeys() once per buffered
row, and that function re-read riinfo->fpmeta each time.  A cast
invoked for one row can accept an invalidation that clears the field,
so the next row found NULL there.  Pass the metadata down from
ri_FastPathBatchFlush() instead, as the array path already did, so one
reference covers the whole batch.  That is only safe because of the
deferred release above; latching without it would turn the NULL
dereference into a use-after-free.

Reported-by: Jacob Brazeal <jacob.brazeal@gmail.com> (offlist)
Reported-by: Brian Carpenter | Deep Fork Cyber <b@deepforkcyber.com>
<offlist>
Reported-by: Anh Khoa <blkhoa2004@gmail.com> (offlist)
Reported-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/CA+HiwqFFB6vzx8v3t2=rbNYyxMistLf5kkJfqzJ81nadFyLrxA@mail.gmail.com
Discussion: https://postgr.es/m/CAJTYsWUFBZNs_UN5MAAK7vG4_DEmv0FiT8552CWuOcggDUki2g@mail.gmail.com
Backpatch-through: 19

2 days agoMessage wording fix
Peter Eisentraut [Wed, 19 Aug 2026 06:56:56 +0000 (08:56 +0200)]
Message wording fix

2 days agoMessage style fixes
Peter Eisentraut [Wed, 19 Aug 2026 06:46:54 +0000 (08:46 +0200)]
Message style fixes

3 days agopsql: Fix psql slash option leaks
Fujii Masao [Wed, 19 Aug 2026 03:37:09 +0000 (12:37 +0900)]
psql: Fix psql slash option leaks

psql_scan_slash_option() returns a malloc'd string, but \getresults,
\gset in pipeline mode, \restrict, and \unrestrict did not free it
after consuming or copying the value.

Free these option strings after use.

Backpatch to all supported versions. In v17 and older, only \restrict
and \unrestrict are affected, so those branches need only that part of
the fix.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEh3R3=1tx_a5=fTDJ+ycuwxWMEn6bG_Yt4B5P+hE7AVw@mail.gmail.com
Backpatch-through: 14

3 days agopsql: Avoid returning oom_buffer from psql slash option scanner
Fujii Masao [Wed, 19 Aug 2026 03:34:28 +0000 (12:34 +0900)]
psql: Avoid returning oom_buffer from psql slash option scanner

psql_scan_slash_option() builds option text in a local PQExpBufferData
and returns the buffer's data pointer to its caller. If either the initial
allocation or a later enlargement failed, that data pointer could be
the static PQExpBuffer OOM buffer rather than malloc-owned storage.
The callers could then eventually pass it to free(), causing undefined
behavior.

Detect a broken option buffer before returning it, report OOM, and return
NULL instead. Also avoid evaluating a backtick substitution when the option
buffer is already broken, since doing so could otherwise touch the static
OOM buffer.

This keeps the existing NULL-return convention for slash options. Callers
are not generally changed to distinguish OOM from no option.

Backpatch to all supported versions.

Reported-by: Junwang Zhao <zhjwpku@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Junwang Zhao <zhjwpku@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEh3R3=1tx_a5=fTDJ+ycuwxWMEn6bG_Yt4B5P+hE7AVw@mail.gmail.com
Backpatch-through: 14

3 days agopsql: Avoid returning oom_buffer from psql slash command scanner
Fujii Masao [Wed, 19 Aug 2026 03:31:00 +0000 (12:31 +0900)]
psql: Avoid returning oom_buffer from psql slash command scanner

psql_scan_slash_command() builds the command name in a local
PQExpBufferData and returns the buffer's data pointer to its caller. If
either the initial allocation or a later enlargement failed, that data
pointer could be the static PQExpBuffer OOM buffer rather than malloc-owned
storage. HandleSlashCmds() could then eventually pass it to free(), causing
undefined behavior.

Detect a broken command-name buffer before returning it, report OOM, and
return NULL instead. Teach HandleSlashCmds() to treat a NULL command name
as a command error before trying to compare or dispatch it.

Backpatch to all supported versions.

Reported-by: Junwang Zhao <zhjwpku@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Junwang Zhao <zhjwpku@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEh3R3=1tx_a5=fTDJ+ycuwxWMEn6bG_Yt4B5P+hE7AVw@mail.gmail.com
Backpatch-through: 14

3 days agoFix relcache reference leak when decoding TRUNCATE
Michael Paquier [Wed, 19 Aug 2026 02:32:40 +0000 (11:32 +0900)]
Fix relcache reference leak when decoding TRUNCATE

ReorderBufferProcessTXN() opens every relation referenced by a
TRUNCATE change.  When RelationIsLogicallyLogged() returns false,
it skips the relation without releasing the reference acquired
by RelationIdGetRelation().

Looking at the in-core code paths building XLOG_HEAP_TRUNCATE records,
no relation OIDs would be included if they do not satisfy
RelationIsLogicallyLogged().  One pattern that could go through is if a
table is switched to SET UNLOGGED, but that would not be reachable in
practice as the decoding happens after a historical snapshot is taken,
so the relation should still be valid.

This is a defense-in-depth measure in practice, and we tend to be
careful about how Relations are handled when sending changes to output
plugins, so backpatch all the way down.

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/7DD65D03-3B5A-43B2-99AD-8E6AF5372BAB@gmail.com
Backpatch-through: 14

3 days agoRelax strictness detection for row-format IS NOT NULL tests
Richard Guo [Wed, 19 Aug 2026 01:24:12 +0000 (10:24 +0900)]
Relax strictness detection for row-format IS NOT NULL tests

find_nonnullable_rels() and find_nonnullable_vars() declined to look
through a NullTest with argisrow set, treating row-format IS NOT NULL
as proving nothing.  But such a test returns FALSE, not TRUE, both
when the composite datum is NULL and when any of its fields is NULL,
so its truth implies a non-null input just as the plain test does.
That is the only property strictness detection relies on, so the
argisrow restriction can simply be dropped.

This lets "a LEFT JOIN b ... WHERE b IS NOT NULL" reduce to an inner
join, the IS NOT NULL counterpart of the whole-row anti-join reduction
in the preceding commit.  make_outerjoininfo() likewise picks up such
tests when it computes join strictness for outer-join ordering.
Row-format tests on composite-type columns now also prove those
columns non-null, which can feed the anti-join proofs.

The stronger implication of a row-format test, that every field of the
row is non-null, remains unexploited: a whole-row Var reported by
find_nonnullable_vars() promises only a non-null datum, since the same
entry can arise from contexts that are merely strict at the datum
level, such as record comparisons.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: wenhui qiu <qiuwenhuifx@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49H9khf+1GwyzD0TYaks6cE-OU+1mbUiOn3gZSoBiO7zg@mail.gmail.com

3 days agoReduce outer joins to anti joins for whole-row IS NULL tests
Richard Guo [Wed, 19 Aug 2026 01:23:44 +0000 (10:23 +0900)]
Reduce outer joins to anti joins for whole-row IS NULL tests

reduce_outer_joins() recognizes "WHERE b.z IS NULL" above an outer
join as an anti-join condition, but not the whole-row "WHERE b IS
NULL", which is a natural way to ask for an anti-join without naming a
specific column.  Teach it to recognize the whole-row form too.

A row that the join null-extends has all of b's columns set to NULL,
so it satisfies "b IS NULL".  A matched row satisfies the test only if
its columns happen to be all NULL.  Hence proving any one column of b
non-null in matching rows rules out every matched row, leaving only
null-extended rows: exactly anti-join semantics.  This mirrors the
single-column case, and the same proofs apply: a NOT NULL table
constraint, a strict join clause (for LEFT joins), or strict quals
within the relation's subtree.  Because any one column suffices, the
whole-row test reduces in a strict superset of the cases a
single-column test does.

To implement this, find_forced_null_vars() now reports a whole-row Var
tested with row-format IS NULL as a varattno-zero entry meaning that
all of the relation's columns are forced null.  Row-format tests on
ordinary composite-type columns remain excluded, since such a test
does not force the column null: it is also true when the column is a
non-null row whose fields are all NULL.  The proof functions in
reduce_outer_joins() treat a whole-row entry accordingly: it is
refuted by proving any one column of its relation non-null.  A match
on the whole-row attribute itself proves nothing, because a non-null
composite datum can still have all columns NULL, so the per-column
matching now explicitly excludes that attribute.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: wenhui qiu <qiuwenhuifx@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49H9khf+1GwyzD0TYaks6cE-OU+1mbUiOn3gZSoBiO7zg@mail.gmail.com

3 days agoReduce FULL JOIN to ANTI JOIN
Richard Guo [Wed, 19 Aug 2026 01:23:09 +0000 (10:23 +0900)]
Reduce FULL JOIN to ANTI JOIN

reduce_outer_joins() already recognizes that a LEFT JOIN is really an
anti-join when an upper qual forces a nullable-side Var to be NULL but
that Var is provably non-null in every row the nullable side emits.
Only null-extended rows can then satisfy the qual, so the matched rows
all drop out and JOIN_LEFT becomes JOIN_ANTI.

The same reasoning applies to a FULL JOIN.  If a forced-null Var on
one side is proven non-null, every row where that side is present,
matched or not, has the Var non-null and is dropped by the qual.  Only
the rows where that side was null-extended survive, which is an
anti-join that keeps the other side's unmatched rows.

When the proven Var is on the RHS, the surviving LHS rows are already
the left input, so this is a plain JOIN_ANTI.  When it is on the LHS,
the surviving RHS rows must become the left input, so we tag the join
JOIN_RIGHT_ANTI and let the existing input-switching step, the one
that flips JOIN_RIGHT to JOIN_LEFT, normalize it to JOIN_ANTI.  Unlike
the LEFT JOIN case, the join's own ON quals cannot serve as proof
here, because they do not hold for the unmatched rows the proof must
cover.

Reducing the full join this way also lets qual constraints reach its
inputs.  reduce_outer_joins_pass2() passes nothing down through a
JOIN_FULL, but it does pass the join's own quals down through the
resulting JOIN_ANTI, so outer joins below it can now be reduced too.
That is sound for the same reason it is for any anti-join: a row that
a lower join null-extends cannot satisfy those quals, so it can never
match, and removing it does not change which rows the anti-join emits.

The proof that a forced-null Var is non-null, from the quals that hold
for every row a subtree emits (optionally plus extra quals the caller
supplies) or from a NOT NULL constraint, is factored into
forced_null_var_is_nonnullable() and shared by the LEFT and FULL
paths.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: wenhui qiu <qiuwenhuifx@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49H9khf+1GwyzD0TYaks6cE-OU+1mbUiOn3gZSoBiO7zg@mail.gmail.com

3 days agoReduce LEFT JOIN to ANTI JOIN using quals within the RHS subtree
Richard Guo [Wed, 19 Aug 2026 01:22:32 +0000 (10:22 +0900)]
Reduce LEFT JOIN to ANTI JOIN using quals within the RHS subtree

reduce_outer_joins() turns a LEFT JOIN into an ANTI JOIN when some Var
that an upper qual requires to be NULL is actually non-nullable in any
matching row.  When that holds, only null-extended (unmatched) rows
can satisfy the upper qual, which is exactly anti-join semantics.
Until now we recognized such a Var as non-nullable only when the
join's own clauses were strict for it, or when it was defined NOT NULL
by table constraints.

This patch allows strict quals applied within the RHS subtree to serve
as the proof as well.  Because such quals hold for every row the RHS
emits, they hold for every matching row, so a Var they force non-null
can become NULL above the join only by null-extension.

To avoid re-walking the jointree at decision time, the first pass of
the reduce-outer-joins process gathers these proving quals into its
per-subtree state, alongside nullable_rels.  The second pass then
proves non-nullness from the RHS subtree's collected quals together
with the join's own ON quals.  As before, the reduction fires only
when the proven, forced-null Var belongs to the RHS of the join.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: wenhui qiu <qiuwenhuifx@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49H9khf+1GwyzD0TYaks6cE-OU+1mbUiOn3gZSoBiO7zg@mail.gmail.com

3 days agoReport single-page checksum failures in pg_stat_database
Michael Paquier [Wed, 19 Aug 2026 00:51:49 +0000 (09:51 +0900)]
Report single-page checksum failures in pg_stat_database

Base backups reported checksum failures to pg_stat_database only for
files with more than one failing page.  Commit 6b9e875f728 placed the
report inside the block emitting the per-file summary WARNING, which
was skipped for a single failure.  As a result, a backup failing on
files with one corrupted page each left checksum_failures untouched.

To fix, emit the per-file summary and the pgstat report for any
non-zero failure count.  The end-of-backup total WARNING had the same
off-by-one and is now also emitted for a single failure.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Discussion: https://postgr.es/m/CAN4CZFN+Bi6XmaH8zOdMWjoycYFx9nKtOr+dzQf0o-UQ+Rdqmw@mail.gmail.com
Backpatch-through: 14

3 days agoMake plperl's handling of Perl hashes more consistent.
Tom Lane [Tue, 18 Aug 2026 21:47:13 +0000 (17:47 -0400)]
Make plperl's handling of Perl hashes more consistent.

Make hek2cstr() available in plperl.h, so that it can be used
in hstore_plperl and jsonb_plperl.  Those modules were previously
using different coding techniques that probably don't get
conversion from Perl strings to the database encoding quite right.
(I'd prefer to make hek2cstr() non-inline, but cross-extension calls
are messy and plperl has avoided them up to now, so stick with the
existing approach.)

Consistently use hv_iternext, hek2cstr, and HeVAL for hash iterations,
with one exception in plperl_trusted_init: there, hv_iternextsv is
fine since we don't actually care about the hash keys.  (A later
patch will remove the HeVAL calls again, but for now we just want
consistency.)

Remove unnecessary extra calls of hv_iterinit.

Remove duplicative pstrdup's in plperl_to_hstore.

The meat of this change is to use hek2cstr() in the contrib modules,
which makes a user-visible change in encoding conversion behavior.
While it's certainly a bug fix, we've had no field complaints about
those modules, so I'm hesitant to make this change in the back
branches.  Hence, apply to master only.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Discussion: https://postgr.es/m/569769.1786901901@sss.pgh.pa.us

3 days agoDefend against null "SV *" pointers in plperl modules.
Tom Lane [Tue, 18 Aug 2026 21:33:44 +0000 (17:33 -0400)]
Defend against null "SV *" pointers in plperl modules.

Tied hashes, and probably tied arrays, are capable of returning Perl
value pointers that are actually NULL, not the usual pointer to an
undef SV.  We were not defending against that everywhere, leading
to possible SIGSEGV.  Fix the code to consistently treat a null
pointer returned from hv_iternext or av_fetch like a !SvOK one.
(Note that the large diff in SV_to_JsonbValue is actually quite
trivial, but it required reindenting a chunk of existing code.)

Claude Code found the instance in hstore_plperl, and I found the
others by code auditing.  Perhaps the other instances aren't
actually reachable, but I see little reason to assume that.

The known test cases for these errors require perl's Tie modules,
which may not be present, so it doesn't seem worth the trouble
to create regression test cases that would cover them.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/569769.1786901901@sss.pgh.pa.us
Backpatch-through: 14

3 days agotest_decoding: Don't print virtual generated columns.
Masahiko Sawada [Tue, 18 Aug 2026 20:55:10 +0000 (13:55 -0700)]
test_decoding: Don't print virtual generated columns.

Virtual generated columns are stored in tuples as null values, so
heap_getattr() in tuple_to_stringinfo() always returns null for them.
test_decoding printed such a column as null, which is
indistinguishable from a column that genuinely holds null.

This commit skips virtual generated columns in tuple_to_stringinfo(),
the only place that prints a tuple. Stored generated columns continue
to be printed, since their values do live in the heap tuple.

This is a behavior change rather than a bug fix, and it changes
test_decoding's output for tables that have virtual generated columns,
which could affect consumers that parse it. Therefore it is not
back-patched.

Author: SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com>
Co-authored-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Euler Taveira <euler@eulerto.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/CAHg+QDfTh3UbB-Ed--o2Bd=SBDJoEiG-qp3C0+ETDibF63y=dw@mail.gmail.com

3 days agoStabilize the FORCE drop test for online data checksums
Daniel Gustafsson [Tue, 18 Aug 2026 20:25:58 +0000 (22:25 +0200)]
Stabilize the FORCE drop test for online data checksums

Commit 51f55b13a4d added a test where DROP DATABASE ... WITH (FORCE)
terminates a session holding a temporary table in the target database.
While exiting, the terminated session drops its temporary table and
commits, and the commit waits for a WAL flush behind the backlog
generated by the checksum workers.  On machines with slow storage this
can exceed the five seconds DROP DATABASE waits for terminated backends
to exit, making the test fail with "database "dropmeforce" is being
accessed by other users", as observed on buildfarm member turaco.

To fix, use asynchronous commit in the terminated session, so that its
exit does not wait for a WAL flush, and checkpoint before the drop so
that the exit-time WAL records do not queue up behind the backlog.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/361531e2-52b5-499c-a126-815f277bbef2@gmail.com
Backpatch-through: 19

3 days agoMinor test suite cleanup
Daniel Gustafsson [Tue, 18 Aug 2026 20:25:55 +0000 (22:25 +0200)]
Minor test suite cleanup

A few catalog queries were missing proper schema qualification in the
test_checksums module test suites, and one suite contained a disable
call right before tearing down the test which can be removed.

Backpatch to v19 where the test suite was added.

Author: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/8CF9B235-AEE9-4E68-93DD-DF4F29E2FCE5@yesql.se
Backpatch-through: 19

3 days agobasebackup: do not verify checksums on pages from before enabling
Daniel Gustafsson [Tue, 18 Aug 2026 20:25:52 +0000 (22:25 +0200)]
basebackup: do not verify checksums on pages from before enabling

Enabling data checksums in a running cluster changes the state to "on"
before the checkpoint which flushes the pages the worker rewrote.  A
base backup which started before that transition absorbs the barrier
mid-run and starts verifying pages whose on-disk copies legitimately
lack checksums, and whose LSNs predate the backup start, so the LSN
check does not skip them either.  The backup fails with bogus
corruption warnings.  The same applies to checksums being disabled and
re-enabled while the backup runs: hint bits set while checksums were
off reach disk without a checksum update and without moving the page
LSN, tripping verification once the re-enabling completes.

To fix, verify checksums only while they have been continuously
enabled since the checkpoint the backup started from: track the
location of the last XLOG2_CHECKSUMS record inserted or replayed, and
verify only when the state is "on" and the last change predates the
backup start.  The starting checkpoint then guarantees that every page
flushed before it has a checksum written, and any later change
disables verification for the rest of the backup.

A standby loses the tracked location when restarting, while pg_control
already carries the new state, so it could reach consistency below the
record and serve base backups with the location unknown.  To prevent
this, replaying XLOG2_CHECKSUMS advances minRecoveryPoint to the
record, like XLOG_PARAMETER_CHANGE does.

The tests hold the enabling between the state change and its final
checkpoint with injection points, straddling it with backups on the
primary and across a standby crash-restart.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CAN4CZFP=-cVVVPue+e8qqPtDfuLuQn=ZB4Mw_C9-Ncru2wqAsQ@mail.gmail.com
Backpatch-through: 19

3 days agoAdd data_page_checksum_version to pg_control_checkpoint
Daniel Gustafsson [Tue, 18 Aug 2026 20:25:49 +0000 (22:25 +0200)]
Add data_page_checksum_version to pg_control_checkpoint

Commit f19c0eccae added the data_checksum_version to the pg_controldata
output, but omitted a corresponding change to the pg_control_checkpoint
SQL function, which reports the same checkpoint information.  The field
is named to match what pg_control_init already reports for consistency.

The integer version reported is an implementation detail which bleeds
through, but it is quite widely used and a more holistic approach to
improving this is left as an excercise for the next major version. The
mapping between states and versions is added to the documentation to
make it easier for users.

Backpatch to v19 where online checksums were introduced.

Author: Ian Barwick <barwick@gmail.com>
Co-authored-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Discussion: https://postgr.es/m/CAB8KJ=hb765sE8bKC-6sh=Yp3sCjN8xs474yuBrkwyoTM2pgZA@mail.gmail.com
Backpatch-through: 19

3 days agoRecord initial state of data checksums in controlfile
Daniel Gustafsson [Tue, 18 Aug 2026 20:25:42 +0000 (22:25 +0200)]
Record initial state of data checksums in controlfile

The controlfile records the current state of data checksums, which
also used to be the initial state from initdb when checksums could
not be altered after initialization.  pg_control_init is documented
to return information about cluster initialization state, which it
no longer will if data checksums have been changed either using the
offline tool or with online processing.

Fix by adding a new field in the control file which tracks the init
value of data checksums, and is left read only after initialization.

While this is a regression dating back to when changing checksum
state was made possible offline with pg_checksums, it is a control
file change so it cannot be backpatched.

Backpatch to v19 where online checksums were introduced.

Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Discussion: https://postgr.es/m/B87ABFBE-A304-4839-8706-C80D73E6BF5C@yesql.se
Backpatch-through: 19

3 days agopg_locale.c: comment improvements.
Jeff Davis [Tue, 18 Aug 2026 20:16:28 +0000 (13:16 -0700)]
pg_locale.c: comment improvements.

Add missing comments and fix outdated/incorrect comments in
pg_locale.c and related files.

Suggested-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/v3nniwcrxejmcfvz56xbd22hphprqleuornd6hqkmw2bl7kgmz@cnytz2ee5ltk
Backpatch-through: 18

3 days agoFix stream abort for a transaction that was never streamed.
Masahiko Sawada [Tue, 18 Aug 2026 18:56:49 +0000 (11:56 -0700)]
Fix stream abort for a transaction that was never streamed.

Commit 072ee847ad4 taught logical decoding to discard the changes of a
transaction that is already known to be aborted when it is picked for
eviction. That path reuses ReorderBufferTruncateTXN(), which marks
every subtransaction that still has in-memory changes as
streamed. Since nothing is streamed in that path, and the top-level
transaction is never marked, a subtransaction ends up flagged as
streamed even though the output plugin has never seen it. Decoding the
subsequent abort record then makes ReorderBufferAbort() invoke the
stream_abort callback for that subtransaction.

For pgoutput this sends a Stream Abort ('A') message to a subscriber
that requested streaming = off, and it does so regardless of the
negotiated protocol version, so even a client speaking a version that
predates transaction streaming receives a message it cannot
parse. test_decoding dereferences a NULL pointer and crashes, since it
allocates its per-transaction state in the begin or stream start
callback, neither of which runs for a transaction discarded as
aborted.

This commit fixes this by marking a subtransaction as streamed only
when it has changes and its top-level transaction is already marked as
streamed. All streaming call sites mark the top-level transaction
before truncating it, so their behavior is unchanged, while the
abort-discard path never marks the top-level transaction and therefore
now leaves its subtransactions unmarked.

Backpatch to v18, where commit 072ee847ad4 was introduced.

Bug: #19616
Reported-by: Tyler Smart <tyler@smarts.io>
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/19616-f6153af509910853@postgresql.org
Backpatch-through: 18

3 days agotest_json_parser: Fix broken file ref and inverted result check
Andrew Dunstan [Tue, 18 Aug 2026 13:06:05 +0000 (09:06 -0400)]
test_json_parser: Fix broken file ref and inverted result check

A comma following a file ref in a perl print statement makes the
statement just print the file's GLOB rather than redirecting the
following arguments to the file. This meant the test was not testing any
contents and the logs were instead bulked up with what the test was
supposed to be testing.

Also, run_log() returns 1 for success, not 0, so the tests for the
return values were wrong. (We were getting 0 because of the comma error
above.)

Backpatch-thru: 17

3 days agoMessage style fixes
Peter Eisentraut [Tue, 18 Aug 2026 12:08:14 +0000 (14:08 +0200)]
Message style fixes

3 days agoRe-register LSN waiters after stale wakeups
Alexander Korotkov [Tue, 18 Aug 2026 11:27:23 +0000 (14:27 +0300)]
Re-register LSN waiters after stale wakeups

WaitLSNWakeup() removes a waiter from the heap before setting its latch.
If the position that caused the wakeup moves backwards before the waiter
rechecks it, as can happen when WAL streaming restarts, the waiter may
sleep again while no longer registered.  Subsequent WAL progress then
cannot wake it.

When an unmet waiter finds that it is no longer in the heap, add it back
and restart the loop.  Rereading the position after registration also
prevents missing an advance between the previous read and the re-add.

Process interrupts before re-registering rather than after, so that a
wakeup which goes stale again cannot postpone cancellation, however often
it repeats.  As a side effect, a pending cancel now wins over an expired
timeout, which previously reported a timeout instead.

Add deterministic TAP coverage that simulates a stale standby_write
wakeup without advancing the actual write or replay positions.

Author: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/CABPTF7UtW_cAa%3DQh4RDfKiUqu3pJJE22ai9tbWJVERbeRyssLw%40mail.gmail.com
Backpatch-through: 19

3 days agoClarify LSN waiter cleanup after wakeup
Alexander Korotkov [Tue, 18 Aug 2026 11:26:38 +0000 (14:26 +0300)]
Clarify LSN waiter cleanup after wakeup

WaitLSNWakeup() can be called by several processes, not only the startup
process.  Update the cleanup comment to explain that another process may
remove the waiter before waking it and that inHeap prevents double
deletion.

Author: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/CABPTF7UtW_cAa%3DQh4RDfKiUqu3pJJE22ai9tbWJVERbeRyssLw%40mail.gmail.com
Backpatch-through: 19

3 days agoAvoid locking when an LSN waiter is already removed
Alexander Korotkov [Tue, 18 Aug 2026 11:25:53 +0000 (14:25 +0300)]
Avoid locking when an LSN waiter is already removed

WaitLSNWakeup() removes each selected waiter from its heap and clears
its inHeap flag before setting its latch.  When such a waiter later
calls deleteLSNWaiter(), it acquires WaitLSNLock exclusively only to
discover that there is nothing left to remove.  Waking many waiters can
therefore make them serialize on the lock for no useful work.

Check inHeap before acquiring WaitLSNLock.  A lockless false value is
conclusive because only the owning backend can change inHeap from false
to true.  A concurrent waker can only clear it.  A stale true value
falls through to the existing recheck under the lock.

WaitLSNCleanup() performed the same lockless check before calling
deleteLSNWaiter().  Drop it there, as it is now redundant.

Author: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/CABPTF7UtW_cAa%3DQh4RDfKiUqu3pJJE22ai9tbWJVERbeRyssLw%40mail.gmail.com
Backpatch-through: 19

3 days agoFix WAIT FOR LSN documentation examples
Alexander Korotkov [Tue, 18 Aug 2026 11:25:03 +0000 (14:25 +0300)]
Fix WAIT FOR LSN documentation examples

Pad example LSNs to match pg_lsn_out() output, and use
"standby_replay LSN" in the timeout error to match the server message.

Author: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/CABPTF7UtW_cAa%3DQh4RDfKiUqu3pJJE22ai9tbWJVERbeRyssLw%40mail.gmail.com
Backpatch-through: 19

3 days agoAdd wait-for-lsn process-exit cleanup callback
Alexander Korotkov [Tue, 18 Aug 2026 11:24:21 +0000 (14:24 +0300)]
Add wait-for-lsn process-exit cleanup callback

WaitLSNCleanup() was called from ProcKill(), but not from
AuxiliaryProcKill(), even though xlogwait.c sizes its shared memory to
include NUM_AUXILIARY_PROCS and thus accepts calls from auxiliary
processes.  Such a process exiting while waiting would leave its entry in
the heap.

Register an on_shmem_exit callback lazily before a process enters a
wait-for-lsn heap instead, as suggested by Noah: that keeps the cleanup
local to xlogwait.c and makes it harder to miss a caller that needs it,
rather than having to remember every process-kill path.

Reported-by: Noah Misch <noah@leadboat.com>
Author: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/20260706012642.f9.noahmisch%40microsoft.com
Discussion: https://postgr.es/m/CABPTF7UtW_cAa%3DQh4RDfKiUqu3pJJE22ai9tbWJVERbeRyssLw%40mail.gmail.com
Backpatch-through: 19

3 days agoFix RI fast-path race with REINDEX CONCURRENTLY
Amit Langote [Tue, 18 Aug 2026 08:06:51 +0000 (17:06 +0900)]
Fix RI fast-path race with REINDEX CONCURRENTLY

The RI fast path reads pg_constraint.conindid before taking
RowShareLock on the referenced table.  REINDEX CONCURRENTLY can
repoint the constraint and mark the old index dead, or drop it,
between those operations.  A backend in that window does not yet
hold a relation lock, so it is not covered by REINDEX CONCURRENTLY's
waits for lockers.

Opening an index that has already been dropped produces "could not open
relation with OID".  Opening one that has only been marked dead can
produce wrong answers: the index is no longer maintained or vacuumed,
so a scan can miss a referenced row or follow a stale entry to a reused
heap line pointer.

After locking the referenced table, reload the constraint and use its
current conindid.  LockRelationOid() processes invalidation messages
after acquiring the lock, so the reload sees a committed index swap.
If the lock was already held, REINDEX CONCURRENTLY cannot mark the old
index dead or drop it until the transaction releases that lock, so
continuing to use the old conindid is safe.

Do this at both RI fast-path call sites.  Add injection-point coverage
for old indexes that have either been dropped or marked dead.

Author: Mihail Nikalayeu <mihailnikalayeu@gmail.com>
Discussion: https://postgr.es/m/CADzfLwUJiVuv69uwuF5z4TrMhNkVwQUXW03q+uVNwmYFLtjEhw@mail.gmail.com
Backpatch-through: 19

4 days agohstore: Rework module to use Size and {add,mul}_size for allocation sizes
Michael Paquier [Tue, 18 Aug 2026 04:44:04 +0000 (13:44 +0900)]
hstore: Rework module to use Size and {add,mul}_size for allocation sizes

hstore has been relying on a set of int/int32 to count the total length
of all the keys and values constructed, relying on the maximum values of
the arguments rather than proper bound checks.  As proved in the
reported thread, these counters could overflow and wrap, leading to
incorrect allocations.

This commit replaces the int/int32 values with a set of Size values,
with add_size() and mul_size() in charge of checking for overflows when
constructing hstore values before doing any allocation.

The changes that matter in terms of the report are mostly in
hstore_io.c.  hstore_compat.c is adjusted for consistency, to keep the
allocation maths uniform across the module.

This is an old bug.  A backpatch should perhaps be done but I cannot get
excited about a change like that in stable branches.

Reported-by: Man Zeng <zengman@halodbtech.com>
Author: Tender Wang <tndrwang@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAHewXNmfD6-9MDxgpRfTzjVj0mhBw3JMoNOHeTiPOjZGhNzd=g@mail.gmail.com

4 days agoFix cross-type foreign keys in the batched fast-path FK check
Amit Langote [Tue, 18 Aug 2026 03:15:51 +0000 (12:15 +0900)]
Fix cross-type foreign keys in the batched fast-path FK check

ri_FastPathFlushArray() rechecked a concurrently updated PK tuple with a
scan key it built itself, putting found_val, the key of the tuple it had
just locked, into sk_argument, and passing that same slot to
recheck_matched_pk_tuple().  Both operands therefore came from the locked
tuple, and since sk_argument is the operator's right-hand input, the PK
value was read as an FK value.  For a foreign key using a cross-type
equality operator, such as a "date" primary key referenced by a "timestamp"
column, that compares days against microseconds, so the recheck always
failed and a batch that had to follow an update chain reported a violation
even though the version it locked still had the key.

Remove the recheck.  For a same-type key it compared the tuple against
itself and so never rejected anything, which was harmless only because the
loop a few lines below does the real work: it already compares found_val,
read after the chain has been followed, against every buffered FK value,
with the arguments in the order the operator expects.  That makes the
recheck redundant as well as wrong.  Detection is not weakened by dropping
it, since the buffered value that led the scan to a tuple can be matched by
no other row visible to our snapshot.

ri_FastPathProbeOne() passes its original scan key, with the FK value still
in sk_argument, and was never affected; nor were single-row statements or
multi-column foreign keys, which go through it.

Add an isolation test covering the cross-type case, a permutation where
the key really does move away, and a same-type permutation that should
behave identically.

Reported-by: Peter Geoghegan <pg@bowt.ie>
Co-authored-by: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-WznQjX3GByh_Ju7unuzMcik_5PJ5D7i_=qhwk=gPEkhfVQ@mail.gmail.com
Backpatch-through: 19

4 days agoDoc: clean up documentation about text search datatype limits.
Tom Lane [Mon, 17 Aug 2026 22:17:51 +0000 (18:17 -0400)]
Doc: clean up documentation about text search datatype limits.

textsearch.sgml neglected to mention that the MAXSTRPOS total-length
limit applies to tsquery as well as tsvector.  It also claims that
there is a 32K limit on the total number of nodes in a tsquery, which
is wrong.  (I suspect that QueryOperator.left may once have been
int16, which would give rise to such a limit.  But it's uint32 now,
so you'd hit the 1GB varlena limit well before overflowing that.)

While at it, re-order the bullet points into an order that makes
more sense, to me anyway.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/455079.1786897319@sss.pgh.pa.us
Backpatch-through: 14

4 days agoTighten up tsqueryrecv().
Tom Lane [Mon, 17 Aug 2026 22:09:07 +0000 (18:09 -0400)]
Tighten up tsqueryrecv().

tsqueryrecv() accepted zero-length lexemes, which tsqueryin() doesn't.
It also accepted phrase distance values larger than MAXENTRYPOS,
which tsqueryin() doesn't.  While neither of these omissions are
very harmful in themselves, they do allow accepting tsquery values
that will fail in a subsequent textual dump/reload.

Commit 23d9ad771 performed similar tightening of tsvectorrecv(),
but I left off these changes at the time because they didn't seem
to have security implications.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/455079.1786897319@sss.pgh.pa.us
Backpatch-through: 14

4 days agoGiST: Deprecate F_TUPLES_DELETED opaque area flag.
Peter Geoghegan [Mon, 17 Aug 2026 21:31:12 +0000 (17:31 -0400)]
GiST: Deprecate F_TUPLES_DELETED opaque area flag.

This flag hasn't been useful since the removal of old-style VACUUM FULL,
so remove it now (this includes removing vestigial code that
unnecessarily set the flag).

Also add test coverage of gistprunepage().  Had that test case been
available before now, the issue fixed by this commit would have been
detected by wal_consistency_checking buildfarm animals.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Michael Paquiër <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAH2-WznbTsQCrjmd=eSawfPqcxCjSFUkk6Qzd3z+gpNte5i03Q@mail.gmail.com
Backpatch-through: 14

4 days agoReorder function prototypes to match definition order
Daniel Gustafsson [Mon, 17 Aug 2026 20:40:26 +0000 (22:40 +0200)]
Reorder function prototypes to match definition order

While purely aesthetic, it makes reading the code easier to rearrange
before the feature has shipped since doing it after risk backpatching
conflicts.  Also add missing prototypes.

Backpatch to v19 where online checksums were introduced.

Author: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEQ1-+iPQnUpTXYiHmzSz9ufFVkOK4kL_uyTdYt7jgg0Q@mail.gmail.com
Backpatch-through: 19

4 days agoMake data checksums launcher cancel its worker at SIGINT
Daniel Gustafsson [Mon, 17 Aug 2026 20:40:22 +0000 (22:40 +0200)]
Make data checksums launcher cancel its worker at SIGINT

Make sure the launcher cancels the currently running worker by calling
TerminateBackgroundWorker when it receives SIGINT.  In order to handle
cases where SIGINT arrives while tje launcher is waiting for a worker
to start or exit, implement a version of WaitForBackgroundWorkerStartup
and WaitForBackgroundWorkerShutdown which checks the abort_requested
signalling.  A new test which kills processing with SIGINT is added.

Backpatch to v19 where online checksums were introduced.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CAHGQGwEQ1-+iPQnUpTXYiHmzSz9ufFVkOK4kL_uyTdYt7jgg0Q@mail.gmail.com
Backpatch-through: 19

4 days agoReplace printf format %i by %d
Peter Eisentraut [Mon, 17 Aug 2026 14:36:40 +0000 (16:36 +0200)]
Replace printf format %i by %d

as is PostgreSQL standard

4 days agoAdd an "unset" value for vacuum_index_cleanup.
Nathan Bossart [Mon, 17 Aug 2026 19:41:59 +0000 (14:41 -0500)]
Add an "unset" value for vacuum_index_cleanup.

This commit adds a new value to StdRdOptIndexCleanup to distinguish
whether it is explicitly set, similar to ViewOptCheckOption's
VIEW_OPTION_CHECK_OPTION_NOT_SET.  This changes only the internal
representation; an unset value still defaults to AUTO, and the
option accepts the same input as before.

This is preparatory work for a follow-up commit that will make use
of the new "unset" state.

Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Tested-by: Greg Burd <greg@burd.me>
Tested-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/aFRxC1W_kZU9OjJ9%40nathan

4 days agoMake plperl's handling of Perl arrays safer and more consistent.
Tom Lane [Mon, 17 Aug 2026 19:06:02 +0000 (15:06 -0400)]
Make plperl's handling of Perl arrays safer and more consistent.

plperl_func_handler()'s stanza for handling an arrayref result in
a SETOF function could loop forever (or at least till OOM) when
given a tied array, since av_fetch won't necessarily ever return
a null pointer in that case.  Be consistent with the other places
where we traverse a perl array: call av_len() once and use len+1
as the loop limit, silently ignoring any null pointers we get back
from that range of subscripts.

But actually, Perl's preferred locution for this seems to be to
use av_count() not av_len()+1.  av_count() seems better since
there's less risk of forgetting to add 1.  Also, both of those
functions return Size_t (or SSize_t) not int, creating at least
a theoretical overflow hazard.  While we're modernizing this,
let's use the correct variable type where we can, and include an
overflow check where we can't.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Discussion: https://postgr.es/m/569769.1786901901@sss.pgh.pa.us
Backpatch-through: 14

4 days agoMake autovacuum_enabled a ternary reloption.
Nathan Bossart [Mon, 17 Aug 2026 18:17:12 +0000 (13:17 -0500)]
Make autovacuum_enabled a ternary reloption.

This commit reimplements autovacuum_enabled as a ternary, using the
support added in commit 4d6a66f675 and following the example of
vacuum_truncate.  This changes only the internal representation: an
unset value still behaves as enabled, and the option accepts the
same input as before.

This is preparatory work for a follow-up commit that will make use
of the new "unset" state.

Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Greg Burd <greg@burd.me>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Tested-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/aFRxC1W_kZU9OjJ9%40nathan

4 days agoRemove extract_autovac_opts().
Nathan Bossart [Mon, 17 Aug 2026 17:16:03 +0000 (12:16 -0500)]
Remove extract_autovac_opts().

extract_autovac_opts() returns a palloc'd copy of just the
AutoVacOpts portion of a relation's reloptions, but upcoming work
needs the other StdRdOptions fields, too.  Remove it in favor of
calling extractRelOptions() directly.  av_relation now caches the
main table's whole StdRdOptions.

Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Tested-by: Greg Burd <greg@burd.me>
Tested-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/aFRxC1W_kZU9OjJ9%40nathan

4 days agoUse safer allocation routines in more places of the tree
Michael Paquier [Mon, 17 Aug 2026 07:15:45 +0000 (16:15 +0900)]
Use safer allocation routines in more places of the tree

This is part of a more global effort to modernize the code tree with
safer allocation functions, which offer more protection in terms of:
- stronger type safety guarantees
- size overflow checks, particulary for arrays.

This set of updates includes allocation changes based on
palloc_object(), palloc_array() and repalloc_array().  This work is
similar to 1b105f9472bd, expanding more the new APIs in the tree in an
incremental fashion.

Author: Tristan Partin <tristan@partin.io>
Discussion: https://postgr.es/m/DKJB5887LGX9.359DV1UMZ1URK@partin.io

5 days agopsql: Fix \d+ display of REPLICA IDENTITY NOTHING
Michael Paquier [Mon, 17 Aug 2026 00:20:52 +0000 (09:20 +0900)]
psql: Fix \d+ display of REPLICA IDENTITY NOTHING

Commit 18954ce7f69 has replaced hardcoded relreplident values in
describe.c with CppAsString2 macros, but used a DEFAULT instead of a
NOTHING at one location.  This caused \d+ on a table with REPLICA
IDENTITY NOTHING to show incorrect data.

Author: Shinya Kato <shinya11.kato@gmail.com>
Discussion: https://postgr.es/m/CAOzEurRHWt+9XLBrbXQOSVkE45NksJ4F28twuqgZ7veW0RzpUQ@mail.gmail.com
Backpatch-through: 18

5 days agoFix ASAN failure after flex errors in GUC file parsing
Michael Paquier [Sun, 16 Aug 2026 23:53:22 +0000 (08:53 +0900)]
Fix ASAN failure after flex errors in GUC file parsing

As detected by ASAN, the scanner value used when parsing GUC files can
be indeterminate when the flex error handler sigjumps to the old cleanup
path, before yylex_init() is called.

The flex scanner state is now made volatile in ParseConfigFp(), since
its value is assigned after sigsetjmp() and cna be accessed after
siglongjmp().  yylex_init() cannot use a volatile pointer; a temporary
variable is used before assigning the result of yylex_init() to it.

While on it, yy_create_buffer() is changed to detect the case where it
returns a NULL value.  Based on my read of the flex code, this cannot be
reached currently.  Future upstream changes or changes in the error
logic of the GUC file parsing could make that reachable, and it is four
extra lines of code.

Oversight in d663f150b5ed.

Reported-by: Ilia Kashintsev <ilia.kashintsev@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Discussion: https://postgr.es/m/19612-24ccb4fc6da7786f@postgresql.org
Backpatch-through: 18

6 days agoClarify logic in CreateSubscription().
Jeff Davis [Sat, 15 Aug 2026 16:42:23 +0000 (09:42 -0700)]
Clarify logic in CreateSubscription().

No bug found in previous code, but it unnecessarily relied on grammar
rules. Per complaint from Coverity.

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

6 days agoAdd previous commit to .git-blame-ignore-revs
Fujii Masao [Sat, 15 Aug 2026 14:26:23 +0000 (23:26 +0900)]
Add previous commit to .git-blame-ignore-revs

6 days agopgindent fix for commit 7b7c4a8dcc9
Fujii Masao [Sat, 15 Aug 2026 14:15:31 +0000 (23:15 +0900)]
pgindent fix for commit 7b7c4a8dcc9

Per buildfarm member koel.

6 days agoRename EXISTS-to-ANY converted subplan to exists_to_any
Fujii Masao [Sat, 15 Aug 2026 09:12:14 +0000 (18:12 +0900)]
Rename EXISTS-to-ANY converted subplan to exists_to_any

Simple EXISTS subplans can be converted to hashed ANY subplans as
an alternative implementation. Previously, both the original EXISTS
subplan and the converted ANY subplan used names with the
exists_ prefix, making EXPLAIN output harder to read and
pg_plan_advice targets less clear.

Use the exists_to_any_ prefix for converted ANY subplans so that
their names distinguish them from the original EXISTS alternative.
This only changes the names shown by EXPLAIN and used by plan advice;
it does not affect planner behavior.

Author: Yugo Nagata <nagata@sraoss.co.jp>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: solai v <solai.cdac@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/20260605165641.3950f99ace0aad8f807abe96@sraoss.co.jp
Backpatch-through: 19

7 days agodoc: Clarify the logging collector's guarantees.
Nathan Bossart [Fri, 14 Aug 2026 20:27:16 +0000 (15:27 -0500)]
doc: Clarify the logging collector's guarantees.

Presently, the documentation for logging_collector says that the
collector "is designed to never lose messages," which reads as a
stronger promise than we actually make.  The collector does not
fsync the log file or retry failed writes, so log messages can go
missing after an operating system crash, power loss, or a write
error.  Reword that sentence and add a note about what is not
guaranteed.

Author: Daniel Bauman <danielbaniel@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Zhenwei Shang <a934172442@gmail.com>
Reviewed-by: Robert Treat <rob@xzilla.net>
Discussion: https://postgr.es/m/CAMtj0_a86DdDKkW-ReVpQpqjndVS6GMrwXVpQY4G3-SGY7saMQ%40mail.gmail.com
Backpatch-through: 14

7 days agoUse correct data type for version identifier
Daniel Gustafsson [Fri, 14 Aug 2026 19:52:21 +0000 (21:52 +0200)]
Use correct data type for version identifier

PGSS_PG_MAJOR_VERSION is written as an uint32 field, but was read back
into an int32.  Fix to make sure reading and writing use the same data
type.

Author: Karina Litskevich <litskevichkarina@gmail.com>
Discussion: https://postgr.es/m/CACiT8iYTkc33YWaA2D3t51Y5s=GqBO7T1zX7bkpSmet2njcLLw@mail.gmail.com

7 days agoUse int64 for number of entries in pg_stat_statements
Daniel Gustafsson [Fri, 14 Aug 2026 19:51:53 +0000 (21:51 +0200)]
Use int64 for number of entries in pg_stat_statements

Commit 13b935cd changed hash_get_num_entries to return int64 instead
of long.  This fixes a few more users of hash_get_num_entries which
were missed in the original commit.

PGSS_FILE_HEADER is left unchanged since this only affects as of yet
unreleased versions of PostgreSQL.  Backpatch to v19 where the int64
change was performed.

Author: Karina Litskevich <litskevichkarina@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CACiT8iYTkc33YWaA2D3t51Y5s=GqBO7T1zX7bkpSmet2njcLLw@mail.gmail.com
Backpatch-through: 19

7 days agoAdd missing PGDLLIMPORT marker.
Nathan Bossart [Fri, 14 Aug 2026 18:41:32 +0000 (13:41 -0500)]
Add missing PGDLLIMPORT marker.

Oversight in commit ffca23839c.

Reported-by: Anton Voloshin <a.voloshin@postgrespro.ru>
Author: Anton Voloshin <a.voloshin@postgrespro.ru>
Backpatch-through: 14

7 days agoRetire PQfn().
Nathan Bossart [Fri, 14 Aug 2026 16:29:21 +0000 (11:29 -0500)]
Retire PQfn().

PQfn() has been documented as somewhat obsolete since commit
efc3a25bb0 (2003), and commit bd48114937 recently marked it unsafe
because it may write past the end of result_buf when result_is_int
is 0.  Furthermore, searches of publicly available code turned up
no callers, only language bindings that expose the function
without using it, so removing it seems unlikely to cause too much
trouble.

Since the symbol is exported, deleting it outright isn't an option,
so instead this commit teaches PQfn() to fail unconditionally with
an error that suggests alternatives.  The documentation for the
fast-path interface is replaced with a stub in the "Obsolete or
Renamed Features" appendix.  The server's fast-path support is
retained for the benefit of older clients and the frontend large
object interface.

The frontend large object interface, the only in-tree caller, now
uses PQnfn(), the private version of PQfn() added by commit
bd48114937.  I considered converting this code away from the
fast-path protocol entirely, but prepared statements can be
deallocated out from under libpq (e.g., by DISCARD ALL), and
PQexecParams() proved noticeably slower, so that is left as a
future exercise.

Reviewed-by: Christoph Berg <myon@debian.org>
Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com>
Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Discussion: https://postgr.es/m/ahXE28klgxIJXBLq%40nathan

7 days agopsql: count every COPY FROM STDIN when scanning a query string.
Tom Lane [Fri, 14 Aug 2026 16:14:23 +0000 (12:14 -0400)]
psql: count every COPY FROM STDIN when scanning a query string.

When SendQuery() is not told how many COPY FROM STDIN commands the
query string contains (as for -c, \gexec, and \watch), it scans the
string to count them itself.  But it called psql_scan() only once,
which stops at the first semicolon, so any COPY FROM STDIN past the
first sub-command was not counted, causing failure of cases that used
to work.  Oversight in commit 3045a25ba.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAN4CZFPqa6c+u4uX5jJ8LANHTQ4dxM3m4_8G9WmX_A4-2wuv2A@mail.gmail.com
Backpatch-through: 14

7 days agoMake generate_queries_for_path_pattern_recurse() interruptible
Peter Eisentraut [Fri, 14 Aug 2026 12:53:50 +0000 (14:53 +0200)]
Make generate_queries_for_path_pattern_recurse() interruptible

In case of a very long path pattern with each element pattern being
resolved to many graph elements
generate_queries_for_path_pattern_recurse() may take very long time to
generate all the possible graph paths.  Make
generate_queries_for_path_pattern_recurse() interruptible so that a
user may be able to cancel such a query if required and the interrupts
are processed in timely manner.

Author: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CAHg%2BQDfDwcM4%3DDSiAV6Ly89YQ5EcMhzO1-9x%3DmGG1WJzODcAig%40mail.gmail.com

7 days agoEnforce WITH CHECK OPTION on DELETE FOR PORTION OF leftovers
Peter Eisentraut [Fri, 14 Aug 2026 09:43:19 +0000 (11:43 +0200)]
Enforce WITH CHECK OPTION on DELETE FOR PORTION OF leftovers

DELETE FOR PORTION OF inserts temporal leftovers through ExecInsert(),
but the rewriter only attached view WCOs for INSERT/UPDATE.  Leftover
rows could therefore silently escape a WITH CHECK OPTION view, while
the equivalent UPDATE correctly raised an error.

This commit fixes it by attaching the WCOs for FOR PORTION OF deletes
too.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Co-authored-by: Paul A Jungwirth <pj@illuminatedcomputing.com>
Reviewed-by: solai v <solai.cdac@gmail.com>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CAN4CZFOuTyhGspG0Nyits8PiK2keoNXkLj-u3APzc66aRcWY9A%40mail.gmail.com

7 days agopostgres_fdw: Rename option "restore_stats" to "import_stats".
Etsuro Fujita [Fri, 14 Aug 2026 08:40:00 +0000 (17:40 +0900)]
postgres_fdw: Rename option "restore_stats" to "import_stats".

The option added by commit 28972b6fc was named "restore_stats", because
it was calling pg_restore_relation_stats()/pg_restore_attribute_stats()
in place of fetching a remote rowsample.  However, those code paths have
been replaced with calls to
import_relation_statistics()/import_attribute_statistics() (cf. commit
54cd6fc83), so the option is now slightly misnamed.

Switch the option to "import_stats", which more closely reflects both
the functions being called internally, and the user's perception of what
the operation is doing.

Back-patch to v19 where commit 28972b6fc went in.

Suggested-by: Etsuro Fujita <etsuro.fujita@gmail.com>
Author: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/CADkLM%3DezuspTk3VD-2EM6XtFP-Dfz7cJKtnbn0cB6gocsAgu1g%40mail.gmail.com
Backpatch-through: 19

8 days agoAdd string-based injection point wait in 051_effective_wal_level.pl
Michael Paquier [Fri, 14 Aug 2026 06:13:30 +0000 (15:13 +0900)]
Add string-based injection point wait in 051_effective_wal_level.pl

This serves as an in-core example of the condition-string API of
injection_points introduced in 0fd73cdffc18, where a wait at the
beginning of a replication slot creation is tightened to happen only for
a specific slot name.

Author: Sami Imseih <samimseih@gmail.com>
Discussion: https://postgr.es/m/CAA5RZ0tsGHu2h6YLnVu4HiK05q+gTE_9WVUAqihW2LSscAYS-g@mail.gmail.com

8 days agoinjection_points: Add support for string comparison in conditions
Michael Paquier [Fri, 14 Aug 2026 05:44:48 +0000 (14:44 +0900)]
injection_points: Add support for string comparison in conditions

injection_points is extended so as a caller can attach a string value to
a point, checked with a value provided at runtime.  There are a couple
of use cases where this can be useful, to be able to target points for
specific object names.

PID and string conditions can be combined together, so as a point can be
allowed for a specific process and string value at the same time.

The condition string is capped at 255 characters.  As the attach SQL
function now takes an optional condition string, it is no longer STRICT,
and rejects NULL inputs.  Empty condition strings are also rejected, as
they don't make sense.

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

8 days agoFix thinko in error of algorithm type lookup for channel binding
Michael Paquier [Fri, 14 Aug 2026 00:45:24 +0000 (09:45 +0900)]
Fix thinko in error of algorithm type lookup for channel binding

The error printed would always use a NULL value, due to OBJ_nid2sn()
known to fail.  This updates the error message to use the algorithm
number instead.

Oversight in 28995f051e72, in the shape of copy-pasto failure.

Reported-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwGPjENxX1SmkPrv9Rb-Fnij8jN4ginObmSTnWXqROS2+g@mail.gmail.com

8 days agoRefactor PgStat_TableStatus to new PgStat_RelationStatus
Michael Paquier [Fri, 14 Aug 2026 00:07:54 +0000 (09:07 +0900)]
Refactor PgStat_TableStatus to new PgStat_RelationStatus

This new structure is split depending on the stats kind it deals with:
- PGSTAT_KIND_RELATION, for tables.
- PGSTAT_KIND_INDEX, for indexes.

This change designs a cleaner barrier for the handling of stats data
related to tables and indexes, by being able to track precisely what are
the counters used by one or the other for pending data.  Using a common
ground for both eases the tracking of Relations in the relcache, with a
structure based on a union separated by stats kind.

The code originally pointed to some counters that may not be used at
all.  For example, indexes have no need for the tracking of
sub-transaction data, still the code implied that these could be touched
for an index.  A consequence is that PgStat_TableXactStatus is not
renamed, as it is not used by indexes.

Some asserts are added as an extra layer of protection to prevent the
update of fields that should not be touched.  find_tabstat_entry() and
find_tabstat_entry_kind() are removed, replaced by a single
find_relstat_entry_kind() able to work for indexes and the rest.

72a6dad1c911 took care of the shared memory and on-disk part of the
split.  This focuses on the pending data part at backend level.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Discussion: https://postgr.es/m/f572abe7-a1bb-e13b-48c7-2ca150546822@gmail.com

8 days agoUse explicit fetching of digests in channel binding (OpenSSL >= 3.0)
Michael Paquier [Thu, 13 Aug 2026 22:37:01 +0000 (07:37 +0900)]
Use explicit fetching of digests in channel binding (OpenSSL >= 3.0)

This commit touches both the libpq and backend-side code of channel
binding where respectively pgtls_get_peer_certificate_hash() and
be_tls_get_certificate_hash() are upgraded to retrieve digests using the
method recommended by OpenSSL 3.0: no more direct EVP_sha256() or
similar, just a EVP_MD_fetch() through EVP to get an algorythm type,
based on a name.

The pre-3.0 code is still required for LibreSSL and as long as we
support OpenSSL 1.1.1.

Similar work has been done in b91f79cd08ab and 1f3b9bb109b8.

Author: Mark Atwood <mark@reviewcommit.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/178596055149.1584250.13974609482797470185@reviewcommit.com

8 days agoFix authorization check for role membership changes.
Nathan Bossart [Thu, 13 Aug 2026 21:35:07 +0000 (16:35 -0500)]
Fix authorization check for role membership changes.

Presently, check_role_membership_authorization() decides whether
the current user may grant or revoke membership in a role by
calling is_admin_of_role(), which recurses through all grants,
while it chooses the grantor to record for the resulting entry by
calling select_best_admin(), which recurses only through inherited
grants.  When the two disagree, the permission check passes and the
grantor lookup then comes up empty, so the user sees an internal
"no possible grantors" error.  ALTER GROUP ... ADD USER reaches the
same error through the separate check in AlterRole().

To fix, teach both checks to search the same way
select_best_admin() does via a new has_admin_privs_of_role().  The
new check passes exactly when the grantor lookup was going to
succeed, so nothing that works today starts failing; the internal
error simply becomes a proper permission error.  Note that this
leaves the other callers of is_admin_of_role() alone, so a role
reachable only through a non-inherited grant can still be dropped,
renamed, or altered.  Whether that ought to change as well is left
as a future exercise.

Oversight in commit ce6b672e44.

Reported-by: ChangAo Chen <cca5507@qq.com>
Author: ChangAo Chen <cca5507@qq.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Pretham <prezza672@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com>
Discussion: https://postgr.es/m/tencent_ADCE2B34B230A9B631854806104FEF40C105%40qq.com
Discussion: https://postgr.es/m/CAJUn_kN%2BMhbb8fYP5xxQCq1KEziOinM6HgYx4ts_pPDnQ2y1nQ%40mail.gmail.com
Backpatch-through: 16

8 days agoReject CLUSTER (ANALYZE).
Nathan Bossart [Thu, 13 Aug 2026 20:28:34 +0000 (15:28 -0500)]
Reject CLUSTER (ANALYZE).

The introduction of the REPACK command also added support for
CLUSTER (ANALYZE).  Presumably this was unintentional, as the
CLUSTER docs make no mention of it.  CLUSTER (ANALYZE) on an
ordinary table succeeds and does indeed analyze the table, but a
database-wide CLUSTER (ANALYZE) or one on a partitioned table
fails with an error like:

    ERROR:  cannot execute REPACK (ANALYZE) on multiple tables

Rather than improving support for CLUSTER (ANALYZE) and thereby
encouraging folks to use CLUSTER instead of REPACK, let's just
reject it.  This commit does so by teaching ExecRepack() to ERROR
for the ANALYZE option in anything except REPACK commands.  Note
that VACUUM (FULL, ANALYZE) does not go through ExecRepack() and
therefore is unaffected by this change.

Oversight in commit ac58465e06.

Reported-by: Zsolt Parragi <zsolt.parragi@percona.com>
Author: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAN4CZFMVcgv1b2G-i%2Bkhs2MDnzWSr7O_53j_x%2BuhAxUV5rwWqw%40mail.gmail.com
Backpatch-through: 19

8 days agoConsistently enforce tsvector/tsquery maximum lengths.
Tom Lane [Thu, 13 Aug 2026 15:20:27 +0000 (11:20 -0400)]
Consistently enforce tsvector/tsquery maximum lengths.

Some places rejected individual tokens longer than MAXSTRLEN, while
others rejected ones longer than MAXSTRLEN-1.  The data structure is
perfectly capable of handling MAXSTRLEN, so there's nothing wrong
with using the looser bound.  Moreover, as things stand there is a
dump/reload hazard: some code paths permit construction of a tsvector
or tsquery that would later be rejected by tsvectorin or tsqueryin.
So standardize on using MAXSTRLEN.

Identical remarks apply to MAXSTRPOS (the total data length),
so fix that too.

Back-patch, in hopes of avoiding cases where a value acceptable to
one supported release is not acceptable to another.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAN4CZFNYQo4zfbRR435uD0vSfuy5y7dnFOXDfKr9zYoL1JnAxA@mail.gmail.com
Backpatch-through: 14

8 days agoFix misc spelling mistakes in comments, docs and tests
Heikki Linnakangas [Thu, 13 Aug 2026 12:04:40 +0000 (15:04 +0300)]
Fix misc spelling mistakes in comments, docs and tests

8 days agoRemove unnecessary #include <poll.h>
Heikki Linnakangas [Thu, 13 Aug 2026 12:03:22 +0000 (15:03 +0300)]
Remove unnecessary #include <poll.h>

Commit cba5b994c9 removed the call to poll() that needed it.

8 days agoFix missing hash_seq_term()
Heikki Linnakangas [Thu, 13 Aug 2026 12:03:15 +0000 (15:03 +0300)]
Fix missing hash_seq_term()

This was harmless because the function (ThereAreNoReadyPortals()) has
only one caller, and that caller throws an error if the function
returns false and transaction abort cleans up the in-progress hash
searches.  But if someone called the function in some other way,
they'd get a warning about a leaked hash_seq_search scan.

8 days agopgcrypto: remove unused field mdc_checked from PGP_Context
Daniel Gustafsson [Thu, 13 Aug 2026 11:18:12 +0000 (13:18 +0200)]
pgcrypto: remove unused field mdc_checked from PGP_Context

mdc_finish used to set this field once it had successfully verified
the MDC packet, with its only reader in the same function.  This was
removed by a59ee881978 when mdc_finish stopped being called through
the pullf_read API, the field has been unused since.

Note that MDC verification does not rely on it: process_data_packets
tracks whether an MDC packet was seen in its local got_mdc variable
and rejects the message if a required MDC is missing, while the
use_mdcbuf_filter path checks the hash in mdcbuf_finish().

Author: Aleksander Alekseev <aleksander@tigerdata.com>
Discussion: https://postgr.es/m/CAJ7c6TNmHnnCkn3uZwRUE7WWYftW--48JFoDVDqoZqMrLYxUZw@mail.gmail.com