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

65009 Commits

Author SHA1 Message Date
Nathan Bossart
f9729b5078 Obstruct EXTRACT() field name deparse injection.
The parser accepts any string as an EXTRACT() field name, but
deparsing does not quote and escape it accordingly.  To fix, quote
and escape the field name during deparsing as needed.  It might be
a good idea to validate the field name during parsing and
deparsing, too, but that is left as a future exercise.

Reported-by: Ben Morris in collaboration with Claude and Anthropic Research
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Etsuro Fujita <etsuro.fujita@gmail.com>
Security: CVE-2026-15741
Backpatch-through: 14
2026-08-10 06:37:49 -07:00
Michael Paquier
57835938fa Fix multirange type handling in pg_restore_attribute_stats()
statatt_get_type() unconditionally converted multirange types to their
underlying range type.  This choice affected all the type information,
like atttypid, atttyptype and operators.

This made the bounds histogram work correctly (range type is required),
but it was wrong for all the other stat kinds.  MCV values for a
multirange column should be parsed as multirange arrays, not range
arrays.  It also made the TYPTYPE_MULTIRANGE check for the range stats
validation as dead code, since atttyptype was always TYPTYPE_RANGE
after the conversion due to the centralized statatt_get_type().

pg_restore_extended_stats() handles the same case correctly: it keeps
the original type and explicitly converts to the range type only at the
point where range_histogram_bounds is built.

The fix of this issue is simple: the multirange-to-range conversion
needs to be moved from the centralized statatt_get_type() up to where
attribute stats build their range_histogram_bounds, matching what is
done for extended statistics restore.

The regression tests for multiranges with attribute stats are extended
to cover this case.

Author: OpenAI Security Research Team
Backpatch-through: 18
Security: CVE-2026-16238
2026-08-10 06:37:49 -07:00
Michael Paquier
3bf185b4bb Reject GSSEncRequest after direct SSL connection
When a direct SSL connection was established, ProcessStartupPacket()
still accepted GSSEncRequest messages.  The GSSAPI negotiation would
then use raw writes and reads, bypassing the TLS encryption layer.
After the GSS encryption was established, the connection continued to
use TLS.  This could betray the HBA rules so as the backend does
protocol exchanges inconsistent with the connection policies in place,
with TLS taking priority over GSS in the backend.

The SSL negotiation path already guarded against attempts to request
SSL after a direct SSL request has been processed.  The GSS path is now
guarded the same way when receiving a startup packet.

Reported-by: p4p3r <kbfanta@naver.com>
Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Jacob Champion <champion.p@gmail.com>
Backpatch-through: 17
Security: CVE-2026-14681
2026-08-10 06:37:49 -07:00
Michael Paquier
c7da85fec9 ecpg: Fix out-of-bound writes due to processing of invalid bytea data
ECPG assumes that any bytea data it receives from a backend starts with
'\x' as its first two bytes, but a check was missed to enforce that.  A
rogue server sending some garbage bytea data would be able to crash a
client, resulting in a client-side DoS, in the most common cases.

Reported-by: ylwangtju <ylwangtju@qq.com>
Backpatch-through: 14
Security: CVE-2026-16241
2026-08-10 06:37:49 -07:00
Heikki Linnakangas
776467301e Use palloc_array() in pltcl and plperl to avoid overflow
Some of these could overflow on 32-bit systems with the right input.
Convert all cases where we called palloc() with multiplication to fix
them. Not all of them were bugs, but it's better to be safe than
sorry.

Reported-by: Tulya Project, Team Dhiutsa, Bitecope Technologies Private Ltd
Backpatch-through: 14
Security: CVE-2026-14677
2026-08-10 06:37:49 -07:00
Heikki Linnakangas
66c2dbb204 Fix pg_trgm's picksplit function with all-true datums
The CACHESIGN.sign field is a BITVECP, not a TRGM, so you should not
use GETSIGN() on it. You don't get a compiler warning because the
GETSIGN() macro includes a cast. It resulted in a bogus read beyond
end of buffer, which would cause bad split decisions or a crash if
you're very unlucky.

Reported-by: Mehmet D. INCE <mehmet@mehmetince.net>
Backpatch-through: 14
Security: CVE-2026-14678
2026-08-10 06:37:48 -07:00
Álvaro Herrera
1e2795ddea pg_stat_statements: Fix buffer overflow with query normalization
Since commit 62d712ecfd, pg_stat_statements has been underestimating
the size of the result buffer possible for a normalized query, in cases
where the query includes many squashable lists, causing the normalized
query to write past the allocated area.

The allocated buffer size forgot to account for the comment appended in
a squashable list, "/*, ... */".  Instead of trying to track down
precisely how much space we need, fix by switch to using an expansible
StringInfo.  This not only fixes the bug, but it also makes the code
simpler to follow.

Author: Álvaro Herrera <alvherre@kurilemu.de>
Reported-by: Sajeeb Lohani with TrendAI Zero Day Initiative
Reported-by: Yuelin Wang <3020001251@tju.edu.cn>
Diagnosed-by: Michaël Paquier <michael@paquier.xyz>
Backpatch-through: 18
Security: CVE-2026-14676
Discussion: https://postgr.es/m/19528-7290dd7e6f7dcc22@postgresql.org
2026-08-10 06:37:48 -07:00
Masahiko Sawada
6713a6e04c Preserve the owner of extended statistics rebuilt by ALTER TABLE.
When ALTER TABLE ... ALTER COLUMN TYPE (or any subcommand that rebuilds
them) drops and re-creates the extended statistics objects depending on
the altered column, the re-created objects were owned by the role running
ALTER TABLE rather than by the original owner of the statistics.

Remember each object's owner before dropping it, and restore it on
re-creation.

CreateStatistics()'s signature changes and CreateStatsStmt gains a field,
but no known third-party code calls the former or constructs the latter.

Author: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-6469
2026-08-10 06:37:48 -07:00
Tom Lane
1aa601b4f5 Return nulls honestly in aggregate "combine" functions.
numeric_combine() and several other state-combining functions for
aggregates cheated for the case of both inputs being NULL: they
returned a null pointer without bothering to mark it as a SQL NULL.
This was harmless in the expected usage where the result would be
passed to the same combine function or a related aggregate final
function.  But it's bad news from a security standpoint, because
now that value can be passed to an internal-accepting function
even if said function is strict.  While a previous patch prevented
such queries from being issued, it seems like good defense-in-depth
to expend the few additional lines of code needed to do this properly.
Comparable functions such as array_agg_combine() already do so.

Reported-by: Amy Burnett (OpenAI Codex Security)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-14680
2026-08-10 06:37:48 -07:00
Tom Lane
8f7e35b08a Reject calls from SQL to functions that take or return type internal.
Allowing that is a security hole, since there are many different
functions with different ideas of what their "internal" argument or
result is.  We already had a defense against the easy case of
"'foo'::internal", but that turns out to be insufficient.  Lock down
both function and operator syntax.  Also disallow attempts to cast to
or from type internal; those would mostly fail anyway, but we have
created some holes with features such as CoerceViaIO.

Reported-by: Amy Burnett (OpenAI Codex Security)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14680
2026-08-10 06:37:48 -07:00
Tom Lane
60e7329b9b Protect some fixed-size arrays that have FUNC_MAX_ARGS elements.
The maximum number of arguments allowed for an aggregate function
is FUNC_MAX_ARGS-1 (since the underlying transfn and/or finalfn
will be called with one more argument).  parse_func.c failed to
enforce this, allowing construction of calls that would try to
pass FUNC_MAX_ARGS+1 to the underlying functions, resulting in
a memory stomp in the executor.  Add correct checking there.

Since it's possible that a bad call has been stored in a view or
SQL function, also add checks in various aggregate-related and
window-function-related code that there are not more than
FUNC_MAX_ARGS arguments.  These will also protect us against the
possibility that we're trying to run a stored view that was made
by a server executable with different FUNC_MAX_ARGS.  (Arguably,
that scenario does not qualify as a security problem.  But let's
just tighten up all of this while we're here, rather than split
hairs over whether an overrun is reachable.)

Likewise check in compute_function_hashkey.  Here the hazard is
directly from a pg_proc row, but the scenario is the same.

PL/Tcl has a similar issue with a fixed-size string buffer.
Let's just replace that buffer with a Tcl_DString, removing the
whole issue and making the code look more like what's around it.

There are a lot of other FUNC_MAX_ARGS-sized arrays, but the rest
have nearby guards already, some with comments explicitly pointing
out the hazard of FUNC_MAX_ARGS changing.

I also used palloc_array() in a few related places in funcapi.c.
Those aren't live hazards AFAICS, but nearby code has been
palloc_array-ified already, so it seemed inconsistent to not use
it here.

Reported-by: Masahiko Sawada <sawada.mshk@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14679
2026-08-10 06:37:48 -07:00
Tom Lane
13bb73aeb6 pg_dump: avoid assuming how long pg_proc.protrftypes can be.
The backend doesn't impose any particular limit on the length of this
array, and since there could be entries for both input and output
arguments, it's feasible for the length to exceed FUNC_MAX_ARGS
even without funny business.  This could lead to crashes or worse.

Moreover, pg_dump shouldn't rely on hard-coding FUNC_MAX_ARGS in the
first place: it has no business assuming that the backend it's dumping
from was compiled with the same value of FUNC_MAX_ARGS that it is.
So the stanza in dumpFunc() that allocates exactly FUNC_MAX_ARGS space
for the parsed OID array is fundamentally misguided.  And it's broken
in another way too: if there are exactly FUNC_MAX_ARGS OIDs, then
parseOidArray won't zero-fill any entries, allowing the subsequent
loop to run off the end of the array.  A crash seems unlikely in
this variant, but garbage output is certain.

To fix, redesign parseOidArray's API so that it does the
array-mallocing, which simplifies the callers anyway.  While we're
here, tighten and modernize it a bit; in particular, split it into
separate functions for OIDs and integers, as was foreseen long ago.
This lets us get rid of the confusing type-punning involved in
having IndxInfo.indkeys be declared as "Oid *" when it's really
potentially-signed ints.  Also, most of the callers expect an exact
number of array entries, so make it verify that not just check for
"too many".

I noted while testing that this dumpFunc() stanza isn't even reached
during check-world.  Add a function with transform to the regression
tests to rectify that.

Reported-by: Masahiko Sawada <sawada.mshk@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Backpatch-through: 14
Security: CVE-2026-19385
2026-08-10 06:37:48 -07:00
Tom Lane
7bd56f7a3b Replace fixed-size, too-short array with a palloc'd one.
MatchNamedCall's arggiven array was declared FUNC_MAX_ARGS long,
but we may actually use up to pronallargs elements, and that can
be more than FUNC_MAX_ARGS if the function has OUT arguments
(cf. ProcedureCreate).  Convert it to a palloc'd array.

Reported-by: Zheng Yu <zheng@depthfirst.com>
Reported-by: ylwangtju <ylwangtju@qq.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14679
2026-08-10 06:37:48 -07:00
Tom Lane
8f0c3d2feb Be more wary about constant's datatype in scalarineqsel().
The special case here for estimating conditions involving a ctid
column failed to check that the RHS constant is of type tid.
While that'd always be true for the built-in operators that
reference this selectivity estimator, a maliciously constructed
operator could provide a user-controlled Datum value that would
get interpreted as an ItemPointer pointer.  That at least risks
SIGSEGV, and perhaps with a bit of sweat it could be used for
server memory disclosure.

Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-14668
2026-08-10 06:37:48 -07:00
Tom Lane
63cb15f40c Harden PL/Perl code against "tied" Perl arrays and hashes.
Tied arrays might report different sizes each time they are inspected.
To avoid generating a corrupt result array, fix plperl_array_to_datum()
to read av_len() of each input array only once.  If the input does
appear to get shorter, we'll fill nulls for the now-missing entries,
which seems fine.  Conversely, if it gets longer, we'll ignore the new
entries.

plperl_to_hstore() assumed that Perl's hv_iterinit() returns the
number of entries in the given Perl hash.  Usually that's true,
but per the Perl docs, "the return value is currently only meaningful
for hashes without tie magic".  That could potentially end in a memory
stomp.  We don't depend on that result value anywhere else, so don't
do so here either.

Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>
Backpatch-through: 14
Security: CVE-2026-14670
2026-08-10 06:37:48 -07:00
Masahiko Sawada
343aabf1d9 Fix potential buffer overrun in regexp match/split functions.
setup_regexp_matches() sizes the buffer used to convert matched
substrings back from pg_wchar form at the smaller of maxlen*eml and
the original string's byte length, on the assumption that such a
conversion cannot produce more bytes than the string it came
from. That assumption holds only for validly encoded input. But
pg_mb2wchar_with_len() silently accepts bytes that are invalid in the
database encoding, turning each such byte into one pg_wchar, and
converting that back can take more bytes than the input did. A string
made of such bytes therefore overruns the conversion buffer by up to
its own length, corrupting the following memory. regexp_match(),
regexp_matches(), regexp_split_to_table() and regexp_split_to_array()
are all affected.

Fix by dropping the tighter bound and always allocating maxlen*eml + 1
bytes.

Reported-by: Francesco Verardi <frevadiscor89@gmail.com>
Author: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-14664
2026-08-10 06:37:48 -07:00
Tom Lane
90649b6f84 Harden tsquery code against overflows.
The only overflow hazards I could find in tsquery construction
are in QTN2QT(), which builds a flat tsquery datum from the
QTNode tree representation used by tsquery_or, tsquery_rewrite,
and allied functions.  There are two:

1. It seems theoretically possible for the outputs of cntsize() to
overflow an int, so I widened them to size_t.  There's no hazard
certainly in tsquery_or and friends, but tsquery_rewrite could expand
the query tree by large multiples (by replacing many identical
subtrees with a large replacement tree), so in a 64-bit machine
with plenty of available memory it should be possible to build a
QTNode tree large enough to cause that.  If these counters did
overflow then we'd under-allocate the output tsquery and have a heap
overwrite problem.  size_t is sufficient, since it's counting the size
of a subset of an in-memory data structure.  We also have to fix the
TSQUERY_TOO_BIG() macro to not get confused if sumlen exceeds
MaxAllocSize.

2. fillQT() neglects to check that the new "distance" value for a
QI_VAL item fits into the available 20-bit field.  It's quite easy
to reach this, for example by tsquery_or'ing two near-megabyte-sized
tsquerys.  However, the result is only a corrupt tsquery that does
not represent the expected query, so perhaps this doesn't rise to
the level of a security bug.  Nonetheless it should be fixed.

Note: I followed the practice used in other tsquery code of checking
each distance value as it's assigned, which means that the last
operand string could extend past the MAXSTRPOS boundary.  This is a
bit different from the pattern used for tsvectors, which insist that
the total data length not exceed MAXSTRPOS and thereby avoid making
per-item checks.  Perhaps that should be harmonized sometime, but for
now it's okay for the two types to do this differently as long as
each one is self-consistent.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Amit Langote <amitlangote09@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14662
2026-08-10 06:37:47 -07:00
Tom Lane
23d9ad7718 Harden tsvector code against overflows.
The core of this patch is to prevent array_to_tsvector() from
generating invalid tsvectors.  It did not check for overly-long
lexemes (so that WordEntry.len fields could overflow), nor did it
check that the total "datalen" fits within MAXSTRPOS (so that
WordEntry.pos fields could overflow, and the number of entries
in the tsvector could be much more than the normal limit).
While the field overflows couldn't do anything much worse than
produce a corrupted tsvector value, a sufficiently large number
of tsvector entries could cause integer overflows in later
processing, such as tsvectorout.

Another important fix is to prevent tsvectorrecv() from accepting
invalid tsvectors.  The main problem there is that it did not
reject empty-string lexemes.  Hence, even though it did (mostly)
enforce the MAXSTRPOS limit, it could still produce a result
with an unreasonable number of tsvector entries, if they were
primarily empty strings.

Also, fix tsvectorout's calculation of its required output
buffer size: it was multiplying the string lengths by
pg_database_encoding_max_length() for no reason.  That contributed
to the risk of integer overflow there.  With valid tsvector input,
there's no risk, but there's still no reason to make the output
buffer several times bigger than needed.

I also tried to make a couple of related routines more robust,
and spent some effort on improving the comments in ts_type.h.
Also, standardize on a single spelling of the "string is too long
for tsvector" message, using %zu instead of an assortment of formats.
These changes aren't security per se but came out of inspecting the
code for problems.

Reported-by: Yuhang Wu <yuhang@depthfirst.com> and Zhenpeng Lin
Reported-by: Zheng Yu <zheng@depthfirst.com>
Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Amit Langote <amitlangote09@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14662
2026-08-10 06:37:47 -07:00
Tom Lane
3d724bf4fd Guard against overlength time zone abbreviations in to_char().
While typical abbreviations are only a few bytes long, a user-supplied
time_zone setting could specify a much longer abbreviation, enough to
overflow to_char's allocation of 12 bytes per format character. If so,
throw an error in the same style as commit 9241c84cb (CVE-2015-0241).

Reported-by: Hcamael <baiyjrh@gmail.com>
Reported-by: Amjad Shahzad <amjadshahzad2000@gmail.com>
Reported-by: Tan Zhen of AntAISecurityLab <TanZhen.AntAI@outlook.com>
Reported-by: Tomer Fichman <tomer@irregular.com>
Reported-by: Zheng Yu <zheng@depthfirst.com>
Reported-by: Amy Burnett (OpenAI Codex Security)
Reported-by: Rick de Jager <rick@v12.sh>
Reported-by: Heewon Song <asteria121@78researchlab.com>
Reported-by: Sylvie Mayer <smayer@cloudflare.com>
Reported-by: Aleksander Alekseev <aleksander@tigerdata.com>
Reported-by: Hillai Ben Sasson <hillai.bensasson@wiz.io>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-14669
2026-08-10 06:37:47 -07:00
John Naylor
19733fa0b4 Rename sort support integer comparators for clarity
The previous names used "unsigned" for Datum-width abbreviated keys
and "signed" for 64-bit signed integers. This may have made more
sense when Datum width was platform-dependent, but commit 805c64f84
added a 32-bit unsigned variant for OIDs, so it makes even less sense
now. Rename all to be explicit about signedness and width.

Suggested-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/CAApHDvrNMz5ahN1x=uK9yscTogmLupfLBy-_qMW9Z+k=HE5u_A@mail.gmail.com
2026-08-10 17:33:46 +07:00
John Naylor
94d32ce1a6 Add ssup_datum_uint32_cmp for comparing OIDs
Commit 51cd5d6f0 used ssup_datum_unsigned_cmp for the OID comparator,
which compares entire Datums. That gave wrong results, since the upper
half of a Datum containing a 32-bit type is not reliably zero-extended:
values fetched from tuples are sign-extended, while values returned
by e.g. oidin() are zero-extended. An OID with the high bit set could
therefore compare as larger or smaller depending on its source.

Fix by adding a sort support comparator that only looks at the low 32
bits. Also teach radix sort to normalize Datums the same way. This keeps
OID eligible for radix sort. Add a regression test that sorts OIDs above
2^31 from both kinds of source, taken from Peter Geoghegan's report.

Reported-by: Zsolt Parragi <zsolt.parragi@percona.com>
Reported-by: Peter Geoghegan <pg@bowt.ie>
Suggested-by: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAN4CZFM2afRzSLJJiWKnRjqPwL7Scm2Wd1xXu140diJGuJtzGg@mail.gmail.com
Discussion: https://postgr.es/m/CAH2-WznvXyKRah=MQ3ONGHiN8ahJcqpmtyikxCOO96A4usDPpg@mail.gmail.com
2026-08-10 17:25:45 +07:00
Daniel Gustafsson
6e89028ec4 Fix errmsg grammar for publication membership
Using "a member of" instead of "member of" is consistent with other
similar error messages.

Author: Peter Smith <peter.b.smith@fujitsu.com>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/CAHut+Pvyj3ad7g-Sb98LDsf1i4c+92rqr+OVG9Lb3fikc_POLg@mail.gmail.com
2026-08-10 08:44:49 +02:00
Michael Paquier
1f3b9bb109 Use EVP_MAC for HMAC (OpenSSL >= 3.0)
The legacy HMAC_CTX interface (HMAC_CTX_new(), HMAC_Init_ex(), etc.) has
been deprecated since OpenSSL 3.0.  The legacy routines do not dispatch
through the provider framework, so a loaded provider's HMAC
implementation could be bypassed.

This commit updates hmac_openssl.c to use EVP_MAC when building with
OpenSSL 3.0 or newer versions.  OpenSSL 1.1.1 is the oldest version
supported on HEAD, so the legacy routines need to be kept.  Note that
LibreSSL uses the legacy routines.

Like b91f79cd08, no backpatch is done.

Author: Mark Atwood <mark@reviewcommit.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/178596055149.1584250.13974609482797470185@reviewcommit.com
2026-08-10 14:53:03 +09:00
Michael Paquier
b91f79cd08 Use explicit fetching for digests in cryptohash (OpenSSL >= 3.0)
cryptohash_openssl.c initialized the EVP_MD_CTX with the implicit static
digest objects (EVP_sha256() and friends).  These do not dispatch
through a loaded provider.  OpenSSL 3.0 and newer versions recommend to
switch to an explicit fetch, using EVP_MD_fetch(), the older routines
being deprecated, available for backward-compatibility purposes.

Now, when building with OpenSSL 3.0 or a newer bersion, we fetch the
digest by name with EVP_MD_fetch(), cache it in the context, and free it
on teardown.  This has as consequence to feed the hash from a provider.
The implicit path is kept for older OpenSSL, 1.1.1 being the oldest
version still supported on HEAD, and for LibreSSL.

This is a slight change in the hashing logic.  No backpatch is done as
that looks safer, and the code in the back-branches is also able to
work.  This has been locally tested across OpenSSL 1.1.1 up to 3.5, so
hopefully nothing is broken.

Note: The submitted code was clearly AI-generated.  I have spend a bit
of time cleaning it up, making it more consistent with the project style
in terms of coding, adjusting a few more things on the way.

Author: Mark Atwood <mark@reviewcommit.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/178596055358.1584287.8485463954311014881@reviewcommit.com
2026-08-10 09:01:46 +09:00
Michael Paquier
127ce77698 Use OOM-safe routine for pgstats shared hashtable insert
pgstat_get_entry_ref() called dshash_find_or_insert() to insert a new
entry into the shared pgstats hashtable.  If the allocation required for
the new entry fails, a local cache entry would be left in
pgStatEntryRefHash with a NULL shared_entry.  This code is switched to
use dshash_find_or_insert_extended(), so as local hash entries can be
cleaned up before failuring.  This change makes pgstat_get_entry_ref()
more robust on re-entry.

Taken in isolation within a single backend, local entries are handled
fine on HEAD as pgstat_get_entry_ref() is able to handle the case of a
NULL shared_entry on re-entry.  However it is possible to finish with
some NULL pointer dereference in more complex scenarios, like:
- First backend fails insert into the shared hashtable on OOM.
- Second backend bumps the same entry's refcount (due to
reinitialization of the same entry, for example).
- First backend calls pgstat_gc_entry_refs(), uses its local entry
reference with the NULL shared_entry, crashes when checking if the
shared entry has been dropped.

6f0738ddec has introduced dshash_find_or_insert_extended() for the
same reason as what we are dealing with here: the backend could be left
in an inconsistent stat, and clean up actions need to be taken before
issuing an error.  The failure is unlikely going to show up in practice,
so no backpatch is done.  This hash insert extended routine is new as of
v19.

Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/anV8ftNMW3xyKSMG@paquier.xyz
2026-08-10 08:37:32 +09:00
Fujii Masao
b597835022 Fix hot standby accepting connections too early after a crash reset
Commit b53b88109f made the postmaster maintain reachedConsistency in
addition to the startup process.  Since the startup process is forked
from the postmaster, it begins life holding whatever value the
postmaster last set.

On a crash reset the postmaster re-forks the startup process while its
own copy still says true: it clears that copy only on receipt of
PMSIGNAL_RECOVERY_STARTED, which the replacement process cannot send
before it exists.  The replacement therefore starts out believing the
database is already consistent.

CheckRecoveryConsistency() then skips the minRecoveryPoint comparison
altogether, so hot standby is announced at redo start while replay may
be arbitrarily far behind minRecoveryPoint.  Read-only connections are
accepted and answer from heap pages that were flushed ahead of the
replay position, returning wrong results with no error raised.  The
same branch also runs XLogCheckInvalidPages() and
CheckTablespaceDirectory(), which are skipped as well, and
log_invalid_page() treats page references that are normal before
consistency as a PANIC.

Fix by clearing reachedConsistency in InitWalRecovery(), so that a
startup process never depends on the value it inherited.  The
postmaster's own copy is deliberately left alone: forked backends read
it to choose the "not yet accepting connections" errdetail, and it
converges once the new startup process sends PMSIGNAL_RECOVERY_STARTED
and, on reaching minRecoveryPoint, PMSIGNAL_RECOVERY_CONSISTENT.

Successive crash resets alternate.  A startup process that skips the
branch never sends PMSIGNAL_RECOVERY_CONSISTENT, so the postmaster's
copy stays false and the next reset forks a process holding the correct
value; that pass reaches consistency properly, which sets the
postmaster's copy back to true and re-arms the problem for the reset
after it.  Roughly every other crash reset is therefore affected, not
just the first one.  EXEC_BACKEND builds are unaffected, as
reachedConsistency is not carried in BackendParameters.

Backpatch to v18, where commit b53b88109f introduced this issue.

Reported-by: Eric Ridge <eebbrr@planetscale.com>
Author: Nikhil Sontakke <nikhil@planetscale.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CA+UBoq2n2Zg9rKgMfUtUohzGssisF9cDeyjKqPrnRNFprEyX1Q@mail.gmail.com
Backpatch-through: 18
2026-08-08 00:09:05 +09:00
Melanie Plageman
69800557ca Only clear VACUUM's read stream strategy once in failsafe mode
112c268380 restored failsafe vacuum's abandonment of a buffer
access strategy by clearing the ReadBuffersOperations' strategy
references. But it did so in lazy_scan_heap()'s main loop, meaning it
looped through all the ReadBuffersOperations once per block after
failsafe was engaged. Track it with a local flag and clear the strategy
only once.

Reported-by: Melanie Plageman <melanieplageman@gmail.com>
Discussion: https://postgr.es/m/CAAKRu_Zse14nSNeCgtnE1LUAH8Of7OmYR%2BCc3O_DAzxt3m6T-g%40mail.gmail.com
Backpatch-through: 18
2026-08-07 10:00:26 -04:00
Amit Langote
0ec3f048bf Handle nullable referenced key in RI fast-path check
The RI fast-path FK check asserted that the referenced key is never
NULL, in ri_FastPathFlushArray() and in recheck_matched_pk_tuple().
That holds for a primary key, but a foreign key may reference any
unique column, and a UNIQUE column is nullable.

The assertion is reachable under READ COMMITTED.  ri_LockPKTuple()
locks the matched PK tuple with TUPLE_LOCK_FLAG_FIND_LAST_VERSION, so
when a concurrent transaction commits a key-changing UPDATE while the
check waits, the lock follows the update chain to the latest version.
If that version now has NULL in the referenced column, the fast path
reaches the assert; in a non-assert build it would compare against the
NULL and treat it as a match.

A NULL referenced key cannot equal any (non-null) FK value, so treat it
as no match and let the ordinary foreign-key violation be raised.  This
matches the SPI path, whose requalifying "pkatt = $n" evaluates to NULL
for such a row, so the row is not returned and the check reports a
violation.

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
Backpatch-through: 19
2026-08-07 17:45:59 +09:00
Amit Langote
dea28d4641 Add previous commit to .git-blame-ignore-revs 2026-08-07 17:45:50 +09:00
Amit Langote
d34f950535 Fix indentation issue introduced by commit 291a4bd2ca
Noticed before the commit reached koel.
2026-08-07 17:38:26 +09:00
Etsuro Fujita
f57df20681 Drain pending asynchronous requests during ExecReScanAppend.
The logic for asynchronous Append assumes that pending requests made for
subplans of an Append are drained during ExecReScanAppend.  To ensure
that, commit 9e283fc85 modified postgresReScanForeignScan to drain such
a request if any, but failed to take into account that if such a request
was made for a subplan that is re-scanned with parameter changes or
pruned in the next round by runtime pruning, the postgres_fdw callback
function is called after ExecReScanAppend or never called, respectively.
This would cause such a request to remain even after ExecReScanAppend,
leading to incorrect results, an infinite loop, or an assertion failure.

To fix, modify ExecReScanAppend to, for each of the pending requests,
give the FDW a chance to drain that request using the existing
ForeignAsyncConfigureWait/ForeignAsyncNotify callback functions.  This
makes the change made to postgresReScanForeignScan useless, so remove it
as well.

Back-patch to v14 where asynchronous Append was added.

Reported-by: Alexander Korotkov <aekorotkov@gmail.com>
Co-authored-by: Alexander Korotkov <aekorotkov@gmail.com>
Co-authored-by: Gleb Kashkin <g.kashkin@postgrespro.ru>
Co-authored-by: Etsuro Fujita <etsuro.fujita@gmail.com>
Reviewed-by: Alexander Pyhalov <a.pyhalov@postgrespro.ru>
Reviewed-by: Gleb Kashkin <g.kashkin@postgrespro.ru>
Discussion: https://postgr.es/m/CAPpHfduMOTnV5Zj2KGJ7zanL_10QvccZHtPUaDfJvBhsh9axnQ%40mail.gmail.com
Backpatch-through: 14
2026-08-07 17:30:00 +09:00
Amit Langote
291a4bd2ca Fire fast-path FK batches inside the deferred trigger loop
AfterTriggerFireDeferred() drained its queued events in a loop, then
called FireAfterTriggerBatchCallbacks() once after the loop to flush
the RI fast-path FK-check batches the fired triggers accumulated.

A batch callback runs user-supplied cast or equality functions, whose
DML can queue further deferred trigger events.  Because the flush ran
after the loop had exited, such an event was left in
afterTriggers.events with nothing to fire it, since
AfterTriggerFireDeferred() is the last drainer at commit.  The deferred
check was skipped and a row violating the constraint committed.

Move the flush inside the loop, after afterTriggerInvokeEvents(), and
drop the "all fired" break, so afterTriggerMarkEvents() re-checks after
each flush and fires events a flush queued at the correct time.  The
other FireAfterTriggerBatchCallbacks() callers leave any queued event
for the eventual commit-time AfterTriggerFireDeferred(), so only the
commit-time firing, which has no later drainer, lost events.

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
Backpatch-through: 19
2026-08-07 17:25:42 +09:00
Amit Langote
7c1c2f0b8d Begin RI fast-path index scan under the switched user id
ri_FastPathCheck() called index_beginscan() before switching to the
referenced relation's owner for the permission check and probe.  For
btree this has no consequence, but starting the scan before the user id
switch sets a poor example for code dealing with out-of-tree access
methods, whose beginscan could observe the wrong user id.  Move
index_beginscan() after the SetUserIdAndSecContext() call.

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
Backpatch-through: 19
2026-08-07 16:33:49 +09:00
Amit Langote
edc92e0ff9 Restrict RI fast-path FK check to btree referenced indexes
The RI fast-path check probes the referenced index directly and, for
single-column keys, uses SK_SEARCHARRAY.  Both assume the index is a
btree.  A comment claimed "PK indexes are always btree", but a foreign
key's referenced index need not be a primary key:
transformFkeyCheckAttrs() accepts any unique (or, for temporal keys,
exclusion) index, so an out-of-tree access method advertising
amcanunique could supply a non-btree index reachable by the fast path.

Add pk_index_is_btree to RI_ConstraintInfo, set from the referenced
index's access method when the constraint is loaded, and make
ri_fastpath_is_applicable() return false for non-btree indexes so such
constraints fall back to the SPI path.

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
Backpatch-through: 19
2026-08-07 16:30:21 +09:00
Amit Langote
ccfa6c9644 Remove stale comment on ri_FastPathCheck()
The note claiming ri_FastPathCheck() is only used by the ALTER TABLE
validation path is no longer accurate.  Rather than reword it, remove
it; the block comment above RI_FKey_check()'s call to the function
already documents when each path is taken, and a duplicated
cross-reference here would only drift out of date again.

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
Backpatch-through: 19
2026-08-07 16:15:47 +09:00
Michael Paquier
bf80a4c2d2 Fix shared refcount leak in pgstat entry acquisition
pgstat_acquire_entry_ref() does an entry acquisition with the following
actions:
- Increment of a shared ebtr's refcount.
- Release dshash partition lock.
- Update local entry_ref fields.

With a pending interrupt, the LWLock acquired by dshash_release_lock()
in the second step could fail, leaving around a local entry_ref with
shared_stats set to NULL and the refcount permanently inflated as
pgstat_release_entry_ref() skips the refcount decrement is shared_stats
is not set.

The actions are now reordered so as the lock is released after the local
entry_ref fields are populated.

The consequence of this problem is a minor leak.  It can only happen if
an interrupt is processed when a dshash lock is released, which is a
very narrow window (very unlikely), so no backpatch is done.

Author: Niall Newman <nn@turacolabs.com>
Discussion: https://postgr.es/m/2FDAA194-9CF3-4FD7-A450-F1A4BEB125F6@turacolabs.com
2026-08-07 14:52:09 +09:00
Michael Paquier
4069df21be Fix local pgstat entry leak on OOM during entry creation
When pgstat_init_entry() fails due to an OOM in the DSA allocation,
pgstat_get_entry_ref() cleaned up the shared hashtable but forgot to
remove the local reference that pgstat_get_entry_ref_cached() had
already inserted into pgStatEntryRefHash.

Missing this cleanup would leave a backend with a stale local cache
entry whose entry_ref points to a NULL shared_stats.  If
pgstat_gc_entry_refs() runs with this reference still around, it would
crash due to a pointer dereference.

The local reference is now removed before removing the shared entry,
the order being sensitive to pending interrupts.

Oversight in 8191e0c16a.

Author: Niall Newman <nn@turacolabs.com>
Discussion: https://postgr.es/m/2FDAA194-9CF3-4FD7-A450-F1A4BEB125F6@turacolabs.com
Backpatch-through: 15
2026-08-07 14:23:28 +09:00
Fujii Masao
44056f6493 Make 030_pg_recvlogical robust against PID reuse
The reconnection test assumed that a restarted walsender would always
have a different PID from the previous one. On some platforms, however,
PIDs can be reused quickly, causing the test to time out even though
pg_recvlogical has successfully reconnected.

This issue was reported by buildfarm member fairywren:
https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=fairywren&dt=2026-07-30%2009%3A58%3A12

Fix this by waiting for the server log message indicating that the
logical replication slot has been acquired again, rather than relying on
a PID change.

Backpatch to v19, where the affected reconnection test was introduced by
commit d89b1d8175.

Author: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/OS9PR01MB121497CF10DFF54F745E37204F5C92@OS9PR01MB12149.jpnprd01.prod.outlook.com
Backpatch-through: 19
2026-08-07 12:30:52 +09:00
Daniel Gustafsson
db0c984b1d Remove scram_client_key_len and scram_server_key_len from PGconn
Commit 761c79508e added scram_client_key_len and scram_server_key_len
to PGconn, but no consumer read the fields and there were no accessor
functions defined.  Code which need the length use SCRAM_MAX_KEY_LEN
which the new fields were also verified to match, so remove the fields
as they are not used.

Author: Aleksander Alekseev <aleksander@tigerdata.com>
Reviewed-by: Matheus Alcantara <matheusssilv97@gmail.com>
Discussion: https://postgr.es/m/CAJ7c6TMx3pyuW86zEjGs4kua0vQPzZEg2sCUe+NnP08fBKuVoQ@mail.gmail.com
2026-08-06 23:27:59 +02:00
Melanie Plageman
112c268380 Restore vacuum failsafe abandonment of buffer access strategy
VACUUM's wraparound failsafe mode exists to reclaim transaction IDs as
quickly as possible. 4830f10243 made the failsafe stop using the
BAS_VACUUM buffer access strategy so that the rest of the vacuum could
make use of all of shared buffers rather than being confined to the
small strategy ring.

However, when 9256822608 made vacuum's first heap pass use the read
stream, this was accidentally disabled. The read stream keeps its own
references to the buffer access strategy, so clearing vacrel->bstrategy
in lazy_check_wraparound_failsafe() no longer had any effect on the
reads issued by the first pass.

Fix this by adding clearing the BufferAccessStrategy reference actually
being used by the ongoing scan -- those in the ReadBuffersOperations
structs themselves.

Two things we accept rather than fix, as neither is worth the added
complexity given how rarely failsafe mode is reached:

- A small amount of read time for IOs that were already in progress when
  the strategy was cleared may be attributed to IOCONTEXT_NORMAL instead
  of IOCONTEXT_VACUUM. WaitReadBuffers() derives the IOContext from the
  (now cleared) strategy, so the wait time of these in-flight IOs is
  misattributed. This is bounded by the stream's look-ahead window and
  happens at most once per vacuum, when the strategy is first cleared.

- The stream's buffer pin limit stays lower than it would have been had
  no strategy been used at all. max_pinned_buffers is capped by the
  strategy's pin limit when the stream is created and is not recomputed
  when the strategy is cleared. Raising it would mean building a new,
  larger ring, which would require first waiting for all in-progress IOs
  to complete. That didn't seem worth it.

Reported-by: Jingtang Zhang <mrdrivingduck@gmail.com>
Discussion: https://postgr.es/m/CAPsk3_APRYVLhAJ5TMwdmpSx8W_%3DPHMm%3DPmKAvnC3gBrfNommQ%40mail.gmail.com
Backpatch-to: 18
2026-08-06 17:22:34 -04:00
Nathan Bossart
5593aca0c6 Remove lo_hton64() and lo_ntoh64().
These functions date back to commit 461ef73f09, which predates the
64-bit byte-swapping routines in pg_bswap.h (added in commit
510b8cbff1).  Commit 0ba99c84e8 converted them to use pg_hton32()
and pg_ntoh32() but stopped short of removing them, so let's do
that now.

Discussion: https://postgr.es/m/ahXE28klgxIJXBLq%40nathan
2026-08-06 13:10:00 -05:00
Daniel Gustafsson
f0178deecb doc: Define MXID as an acronym
XID is defined as an acronym in the documentation but MXID (Multixact
ID) was missing from the acronym list.  This adds MXID as an acronym
and links it to the "Multixacts and Wraparound" section.

Author: Koshino Taiki <koshino@sraoss.co.jp>
Discussion: https://postgr.es/m/OS9PR01MB17364A940ACFCADBB7593498A94D32@OS9PR01MB17364.jpnprd01.prod.outlook.com
2026-08-06 14:07:57 +02:00
Peter Eisentraut
9b917a9311 Report duplicate property and label names with a proper error
Adding a property with the same name multiple times to a label on an
element, either within a single PROPERTIES clause or across statements
via ALTER PROPERTY GRAPH ... ADD PROPERTIES, previously failed with a
unique-index violation on pg_propgraph_label_property.  The same class
of bug existed for labels: listing the same label multiple times on
one element in CREATE PROPERTY GRAPH, or adding a label to an element
that already has it via ALTER PROPERTY GRAPH ... ADD LABEL, failed
with a unique-index violation on pg_propgraph_element_label.  Detect
the duplicates up front and raise a friendlier error in both cases.

For properties, the cross-statement duplicate is caught by a syscache
probe before insertion.  The in-clause duplicate could have been
caught by the same probe if we issued a CommandCounterIncrement()
between property inserts, but that forces a catalog invalidation per
property purely to detect a condition we can check for free on the
in-memory target list.  The list-based check is only needed when the
properties are listed explicitly; when they are derived from the
table's attributes, names are already unique.

For labels, a single syscache probe on pg_propgraph_element_label
suffices for both the in-clause and cross-statement cases because
insert_element_record() already issues CommandCounterIncrement()
between successive label inserts.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://www.postgresql.org/message-id/flat/20260630173053.51.noahmisch%40microsoft.com
2026-08-06 10:42:05 +02:00
Michael Paquier
290bb8afe6 Tighten proto_version parsing in pgoutput
This is similar to 58ff4a0a08, but this time for the parameter
"proto_version", when given as a parameter to pgoutput for logical
replication.  strtoul() lacked a check for an empty string, leading to
an inconsistent behavior depending on the platform.

The author has originally proposed a TAP test to check this empty value
pattern.  I have added a cheaper SQL query, instead, test_decoding
including a test area where this is possible.

Author: Tristan Partin <tristan@partin.io>
Discussion: https://postgr.es/m/DKBS2Z9CGARC.2T07O6TJYSE8B@partin.io
2026-08-06 16:46:03 +09:00
Michael Paquier
58ff4a0a08 Tighten tid input parsing with strtoul() to reject empty fields
strtoul() informs that in the case of no conversion, "endptr" is set
equal to the location of the input pointer, which is something that
tidin() has never checked.

This allowed inputs like "(,)", "(1,)" or "(,1)" to be accepted on some
platforms, like Linux where "(1,)" implied "(1,0)", but rejected on
others like macos where "(1,)" is rejected, due to the fact that errno
may not be set.

This change may cause some issues as some tid values will now be
rejected, but at least we get the consistent strtoul() experience.
If it proves to be a pain for some, it could always be reverted.
Another point of this change is that we get one step closer to a
possible common strtoul() where the error handling could be unified in
core, with all the errors handled the same way for errno and no input
parsed, at least.

Reported-by: Michael Malis <malis@pgrust.com>
Author: Tristan Partin <tristan@partin.io>
Discussion: https://postgr.es/m/19584-e60c446ba6f57c9c@postgresql.org
Discussion: https://postgr.es/m/DKBS2Z9CGARC.2T07O6TJYSE8B@partin.io
2026-08-06 15:39:56 +09:00
Amit Kapila
4790abd112 Fix race condition in subscription TAP test 023_twophase_stream.
Buildfarm member olingo intermittently failed this test, timing out while
waiting for the subscriber log to report an ERROR because
max_prepared_transactions is zero there. The test captured the log offset
only after issuing the publisher's
BEGIN/INSERT/PREPARE TRANSACTION/COMMIT PREPARED sequence.

Since streaming is enabled, the subscriber can receive and apply the
transaction, and log the expected ERROR, before that publisher SQL command
even returns, i.e. before the test captures the offset. The subsequent
wait_for_log() calls then searched only from a point after the message had
already been written, and timed out waiting for it.

Fix by moving the offset capture to before the publisher's transaction is
issued, ensuring it always precedes the point where the ERROR can appear
in the subscriber log.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Zhijie Hou <houzj.fnst@fujitsu.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 16, where test was introduced
Discussion: https://postgr.es/m/c43753d8-5265-4f77-83ff-9b1167276ec5@gmail.com
2026-08-06 11:41:18 +05:30
David Rowley
d260d7d003 Fix unlikely incremental tuple deform bug with missing attrs
The code added in c456e3911 added populate_isnull_array() to bulk
populate the slot's tts_isnull array 8 elements at a time.  When tuples
don't have an exact multiple-of-eight number of attributes, this will
lead to populating the tts_isnull elements for attributes that don't
exist in the tuple.  This is ok as the array is large enough.  However,
if we perform tuple deforming in two passes, and on the first pass
deform *some* of the attributes with slot_getmissingattrs() then later
when we deform the remaining missing attributes, the subsequent call to
populate_isnull_array() would overwrite the tts_isnull values previously
set by slot_getmissingattrs(), and since that function only continues
where it left off, it wouldn't reapply the previously set values and those
would be left as NULLs, as populate_isnull_array() would have set them.

Here, we fix by passing the tuple's natts to slot_getmissingattrs()
rather than the attnum we're deforming from.  This means we apply all
the missing attribute values each deform pass, so slightly more work,
but deforming several missing values in different deform passes is
likely exceedingly rare.  Doing that seems much better than adding
overhead in the happy path to check for this and skip the subsequent call
to populate_isnull_array().

Author: David Rowley <dgrowleyml@gmail.com>
Reported-by: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-WznHo4b+6AmAj0GZ0jXqDSK69MfHe8fAQwuY_01y7cVNdw@mail.gmail.com
Backpatch-through: 19
2026-08-06 17:42:44 +12:00
Michael Paquier
1200dfd60c Remove redundant unlink() in KeepFileRestoredFromArchive() for non-WIN32
KeepFileRestoredFromArchive() called unlink() on an existing WAL segment
before durable_rename() replaced it.  rename(2) atomically replaces a
target on POSIX systems, and the extra unlink() created a small window
where it would be possible for a concurrent WAL sender to see a segment
as missing.

Note that the window still exists on WIN32, as we lack a safe concurrent
alternative.  Perhaps something like ReplaceFile() could be looked at
for this purpose.

This problem is hard to reach in practice, so no backpatch is done.  I
also tend to be conservative regarding recovery changes, even small, in
stable branches.

Author: Stepan Neretin <slpmcf@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Reviewed-by: Neil Chen <carpenter.nail.cz@gmail.com>
Discussion: https://postgr.es/m/CA+Yyo5S0C25jS_pRWQiGgoiy+X=GyJS7ZJkEq=_SW1WWpkL3Sg@mail.gmail.com
2026-08-06 08:19:13 +09:00
Jeff Davis
7f4fb05807 When changing owner of a subscription, do not throw an error.
Errors will be caught when the connection is actually used.

Restore uses multiple DDL commands to restore a subscription, so
checks of the intermediate state risk restore errors. In the future we
could address this with a more careful restoration order, but the
DDL-time errors are merely for convenience.

Addresses finding 2 in the report from the linked discussion.

Reported-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Shlok Kyal <shlok.kyal.oss@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/20260710195902.4f.noahmisch%40microsoft.com
Discussion: https://postgr.es/m/e103ae8daf74485e0c0ebde297fae735d38f54d1.camel@j-davis.com
Backpatch-through: 19
2026-08-05 13:19:21 -07:00
Jeff Davis
ac230cd3ce Revert "Validate subscription conninfo on owner change"
This reverts commit 1c9c358904.

Raising errors during OWNER TO can cause problems during restore. An
upcoming commit will avoid other errors that can happen in this path.

Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/e103ae8daf74485e0c0ebde297fae735d38f54d1.camel@j-davis.com
Backpatch-through: 19
2026-08-05 13:19:10 -07:00