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

62579 Commits

Author SHA1 Message Date
Nathan Bossart
0ddd9098a3 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:38:12 -07:00
Michael Paquier
08454e8b2d 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:38:12 -07:00
Michael Paquier
8d428c6e67 Add test with multirange type for pg_restore_attribute_stats()
This commit adds a test for pg_restore_attribute_stats() with the
injection of statistics related to a multirange type.  This case is
supported in statatt_get_type() since its introduction in ce207d2a79,
but there was no test in the main regression test suite to check for the
case where attribute stats is restored for a multirange type, as done by
multirange_typanalyze().

Note that this has been originally applied as d4504d6f60 in v19 and
newer branches.  This will be used for the test of a follow-up commit.

Author: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/CADkLM=c3JivzHNXLt-X_JicYknRYwLTiOCHOPiKagm2_vdrFUg@mail.gmail.com
Security: CVE-2026-16238
Backpatch-through: 18
2026-08-10 06:38:12 -07:00
Michael Paquier
203a48209a 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:38:11 -07:00
Michael Paquier
a14ba29b15 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:38:11 -07:00
Heikki Linnakangas
028ee716a7 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:38:11 -07:00
Heikki Linnakangas
849019a50a 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:38:11 -07:00
Álvaro Herrera
8a31ffc2d4 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:38:11 -07:00
Masahiko Sawada
a1fa24127d 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:38:11 -07:00
Tom Lane
722695db18 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:38:11 -07:00
Tom Lane
54649de65f 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:38:11 -07:00
Tom Lane
2a03f21daf 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:38:11 -07:00
Tom Lane
3392cce5c9 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:38:11 -07:00
Tom Lane
7f0e1aac7a 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:38:11 -07:00
Tom Lane
a2cb5a1cfb 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:38:11 -07:00
Tom Lane
87c4b82197 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:38:11 -07:00
Masahiko Sawada
b7e5c3f634 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:38:10 -07:00
Tom Lane
dddc8a69ff 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:38:10 -07:00
Tom Lane
e251350573 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:38:10 -07:00
Tom Lane
4fafe23805 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:38:10 -07:00
Peter Eisentraut
3d3462a6d9 Translation updates
Source-Git-URL: https://git.postgresql.org/git/pgtranslation/messages.git
Source-Git-Hash: cebe759464bfe8207fc3d3c2a0c6f79474fb4d1c
2026-08-10 12:14:04 +02:00
Tom Lane
a4c41bbcc7 Release notes for 18.5, 17.11, 16.15, 15.19, 14.24. 2026-08-09 12:52:47 -04:00
Tom Lane
828d602f21 First-draft release notes for 18.5.
As usual, the release notes for other branches will be made by cutting
these down, but put them up for community review first.
2026-08-07 13:11:52 -04:00
Fujii Masao
311e66df9c 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:10:06 +09:00
Melanie Plageman
7c25cdb1eb 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:06:41 -04:00
Etsuro Fujita
4ea497a926 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:02 +09:00
Michael Paquier
2fd8d45ecf 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:35 +09:00
Melanie Plageman
585181e077 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:31:22 -04:00
Amit Kapila
b37f14875a 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:26:57 +05:30
Melanie Plageman
ed8050370b Make local buffers pin limit more conservative
GetLocalPinLimit() and GetAdditionalLocalPinLimit(), currently in use
only by the read stream, previously allowed a backend to pin all
num_temp_buffers local buffers. This meant that the read stream could
use every available local buffer for read-ahead, leaving none for other
concurrent pin-holders.

In 18, this was reported as a sequential scan of a temporary table
failing with "no empty local buffer available": with
effective_io_concurrency >= 64 and default io_combine_limit and
temp_buffers, the scan's read stream budget,
(effective_io_concurrency + 1) * io_combine_limit, meets or exceeds
num_temp_buffers, so look-ahead could pin the entire local buffer pool.
Any additional pin request made while returning tuples -- such as
fetching TOASTed values from the table's (also temporary) TOAST table --
then found no unpinned buffer to evict.

Cap the local pin limit to num_temp_buffers / 4, providing some
headroom. This doesn't guarantee that all needed pins will be available
-- for example, a backend can still open more cursors than there are
buffers -- but it makes it less likely that read-ahead will exhaust the
pool.

This is a backpatch of commit da6874635d, which was applied to master
only during the 19 development cycle, where the issue surfaced as a
regression test failure after on-access pruning began setting the
visibility map. Reports of the failure above on 18 prompted
backpatching it now.

No backpatch to 17, even though its read stream also allows a single
stream to pin the whole pool in principle. There, sequential scans pass
READ_STREAM_SEQUENTIAL, which disables fadvise-based look-ahead, so the
look-ahead distance cannot grow past io_combine_limit (at most 32
buffers, versus a minimum temp_buffers of 100) and the reported failure
is unreachable. The remaining theoretical paths require adversarial
settings and have never been reported. Moreover, 17 predates these
functions; the fix would have to be reimplemented in
LimitAdditionalLocalPins(), making the change not a simple cherry-pick.

Reported-by: Induja Sreekanthan <indujas@google.com>
Reported-by: Eduard Stepanov <crtxcz@gmail.com>
Reported-by: Feike Steenbergen <feikesteenbergen@gmail.com>
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/97529f5a-ec10-46b1-ab50-4653126c6889%40gmail.com
Discussion: https://postgr.es/m/flat/CAFMO8-rYPSJbXsDdWDzDdpNi-fQ%2B6bKvgbXwE%2BR%3DsGko4epq0Q%40mail.gmail.com
Backpatch-through: 18
2026-08-05 11:44:01 -04:00
Álvaro Herrera
011384ba45 Fix calculating length of match to localized month/weekday names
seq_search_localized() returns the length of the matching prefix in
*len, but because it internally case-folds the inputs, it gets
confused on the length. The caller expects to get the length of the
prefix in the original string, but what it actually returns is the
length of the prefix after case-folding, which can be different if the
case-folded characters have different byte-length than the original,
or with ICU, if the case-folding changes the number of characters
(e.g. "ß", the German double s).

To fix, once we have determined that we have a match, work harder to
find the match's length in the original string.  This adds some
overhead, but the strings are expected to be short.

The function does "case-folding" by converting a string to upper-case,
then to lower-case, which is a little ugly given that we have
dedicated functions for case-folding nowadays. But switching to that
doesn't seem appropriate to backpatch in a security fix, and that's
not available in older stable versions, anyway.

Author: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Reported-by: Xint Code
Reviewed-by: Jeff Davis <pgsql@j-davis.com>
2026-08-05 11:40:39 +02:00
Fujii Masao
13a9be148e doc: Update XID wraparound error example
Commit edee0c621d, and the equivalent v17 commit f2353dd717,
changed the runtime XID wraparound messages to use "transaction IDs"
terminology, but one corresponding error example in maintenance.sgml
still used the older XID wording.

Update that documentation example in line with the current runtime
message.

Backpatch to v17, where the runtime messages were changed.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Yugo Nagata <nagata@sraoss.co.jp>
Discussion: https://postgr.es/m/CAHGQGwHTN-Xc5iDtbzNSjfxuab5Y9qAArw8cB4PrrDJpZ+1fgA@mail.gmail.com
Backpatch-through: 17
2026-08-05 11:37:39 +09:00
Álvaro Herrera
19f0391df4 pg_surgery: Fix infinite loop on large TID arrays
heap_force_common() tracked the current position in the caller-supplied
tid[] using OffsetNumber, which is only 16 bits wide, so when the array
held more than 65535 entries, the updated index wrapped around and the
outer loop never reached the exit condition.  A SQL call with a
sufficiently large TID array would then run until interrupted.

Fix by tracking the tid[] position using int instead of OffsetNumber.
A regress case based on the report is included.

Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Reported-by: Yuelin Wang <1217816127@qq.com>
Backpatch-through: 14
Bug: #19607
Discussion: https://postgr.es/m/19607-2f256a66481c514b@postgresql.org
2026-08-04 11:44:11 +02:00
Fujii Masao
6b46a5d1b6 Fix error handling in getCopyDataMessage() and pqFunctionCall3()
Commit f6f0542266 changed getNotify(),
getParameterStatus(), and related libpq message-processing paths to
abandon the connection on out-of-memory errors.

However, getCopyDataMessage() and pqFunctionCall3() did not handle
this new fatal-error state. Both can process asynchronous
NotificationResponse and ParameterStatus messages while waiting for
other responses. If one of those messages triggered a fatal error, these
loops continued processing instead of reporting it immediately.

Fix this by checking for a saved fatal error after processing an
asynchronous message. If the connection has been abandoned, return the
appropriate error immediately instead of continuing to parse input.

Backpatch to v18, where commit f6f0542266 introduced this issue.

Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAO6_XqpGfm+XHE1OzS=_+jroeDOxhhGa11P3cbm9q2gT05yorA@mail.gmail.com
Backpatch-through: 18
2026-08-04 17:05:44 +09:00
Álvaro Herrera
c374f2807c Fix ALTER COLUMN ... DROP EXPRESSION with subpartitions
Per commit 8bf6ec3ba3, a column can be GENERATED only if it is such in
the whole inheritance tree.

For this reason, ATPrepDropExpression refuses to be called with ONLY on
a partitioned table. To detect this, the current implementation checks
whether recurse is set to false and the rel has direct children.

Recursion is implemented with ATSimpleRecursion, which calls ATPrepCmd
with recurse = false for every node in the tree. Inner nodes (for
example a partition which itself has subpartitions) then fail the check,
accidentally preventing the command from working on inheritance trees of
depth > 2.

This commit fixes it by also checking that we're at the top level of the
recursive calls using the recursing parameter, which is always true when
called through ATSimpleRecursion, always false when invoked on the root
rel.

Also, remove a comment claiming that DROP EXPRESSION could be
implemented with some effort.  It cannot, as the commit message for
8bf6ec3ba3 explains.

Author: Alberto Piai <alberto.piai@gmail.com>
Backpatch-through: 14
Discussion: https://postgr.es/m/DHMT78XOD8BK.341V3H87KZ7NO@gmail.com
2026-08-04 09:06:46 +02:00
David Rowley
6298a41b4e Fix missing money overflow checks for INT64_MIN / -1
Similar to what 1f7cb5c30 did for the INT types, protect against
overflow when dividing the lowest possible money value by -1.  This
cannot be represented on a two's complement machine.

Without this check, the result depends on the machine, and in the worst
case, could result in a crash.  With the fix installed, this will now
result in:

ERROR:  money out of range

Bug: #19585
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reported-by: Michael Malis <malis@pgrust.com>
Reviewed-by: Tristan Partin <tristan@partin.io>
Reviewed-by: Rafia Sabih <rafia.pghackers@gmail.com>
Discussion: https://postgr.es/m/19586-bb603bf5ad9934dd%40postgresql.org
Discussion: https://postgr.es/m/CAB8bMisnXJVXte6s3kUOpuuAY9%3D9kehG6MMX-%2BTQoFsSGan22Q%40mail.gmail.com
Backpatch-through: 14
2026-08-04 18:00:27 +12:00
David Rowley
bf048f0e17 Fix missing MCXT_ALLOC_NO_OOM handling in MemoryContextAllocAligned
Fix missing NULL check in MemoryContextAllocAligned().  The underlying
call to MemoryContextAllocExtended() could return NULL when
flags contains MCXT_ALLOC_NO_OOM and the underlying malloc fails.

There are no current callers using MemoryContextAllocAligned() that pass
the MCXT_ALLOC_NO_OOM in core, so no live bug fix in core here. However,
an extension might use this pattern, so we'd better fix.

Fix this so we correctly pass the NULL to the caller rather than trying
to write to a NULL memory address.

This also fixes the same bug in AlignedAllocRealloc(), which is also
unused in core.

Backpatch to v16, where these functions first appeared.

Author: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/07DAC4C3-120D-4F3C-8FEE-BA236F7E9C1D@gmail.com
Backpatch-through: 16
2026-08-04 16:09:55 +12:00
Jeff Davis
a0daa0b412 Fix lock release for role membership grants in DROP OWNED BY.
Commit 6566133c5f added a case for AuthMemRelationId in
AcquireDeletionLock(), but not ReleaseDeletionLock(). The fall-through
case would go to UnlockDatabaseObject(), which would raise a WARNING;
and the lock would be retained until the end of the transaction.

Add the missing branch.

Discussion: https://postgr.es/m/2487ddcd737d4fc8e408e87aa9ad4365eed3bbb3.camel@j-davis.com
Backpatch-through: 16
2026-08-03 12:25:31 -07:00
Jeff Davis
9a8c933837 Do not log subscription conninfo.
Logging connection information, even at DEBUG1, creates unnecessary
risks. Remove the entire log message because it had no other useful
content.

Addresses finding 14 in report from linked discussion.

Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/20260710195902.4f.noahmisch@microsoft.com
Backpatch-through: 14
2026-08-03 11:35:41 -07:00
Álvaro Herrera
d04a24d9ea Remove unused arg and dead code in set_attnotnull()
The is_valid parameter was never referenced in the function body, and
the 'thisatt' local variable is set but never used.  Remove both.

Oversight in a379061a22.

Author: Sami Imseih <samimseih@gmail.com>
Backpatch-through: 18
Discussion: https://postgr.es/m/CAA5RZ0tHnvSrfUy4jWJchjvkL_aJe0hCnZpMsFRdLrSxCne5qQ@mail.gmail.com
2026-08-03 13:52:41 +02:00
Tom Lane
81b1e79166 Tighten up TS dictionary cache entry creation.
In the not-too-likely scenario where we successfully created a hash
table entry for a TS dictionary, but then failed to make a small
memory context for it, we left the hash entry in existence but with
a garbage value for dictCtx.  This confused the code the next time
through, leading to a crash.  Rearrange things so that we leave
the hash entry in a well-defined state with dictCtx == NULL, and
then the next try knows it still needs to make a memory context.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/0f3ddeb5-0dbd-479c-9d0e-ae254758e624@gmail.com
Backpatch-through: 14
2026-08-02 16:49:18 -04:00
Tom Lane
4689ea9cee Fix memory-safety bugs in the ispell/hunspell dictionary loader.
Allocate CompoundAffix with room for its terminator, initialize the
old-format flag buffer before NIAddAffix(), and reject incomplete or
missing Hunspell AF aliases.  None of these errors would be likely to
trigger on real dictionary files, accounting for the lack of previous
reports; but they're certainly bugs.

Bug: #19595
Reported-by: Michael Malis <michaelmalis2@gmail.com>
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19595-7dc18b4e212c4757@postgresql.org
Backpatch-through: 14
2026-08-02 13:22:39 -04:00
Tom Lane
5f67124fa4 Update time zone data files to tzdata release 2026c.
Alberta (America/Edmonton) moved to permanent UTC-06 on
2026-06-18, which will affect their clocks beginning on 2026-11-01.
For lack of any clarity on the point, assume their TZ abbreviation
will be CST from that time forward.

Morocco (Africa/Casablanca) will move to permanent UTC+00,
without daylight saving time transitions, on 2026-09-20.

Backpatch-through: 14
2026-08-02 11:26:30 -04:00
Jacob Champion
74169d3a1d libpq-oauth: Avoid overflow for very large intervals
The slow_down interval parsing code checks explicitly for overflow, but
since it does that after the signed overflow has already occurred, we
end up inviting undefined behavior from the compiler anyway.

Use checked arithmetic instead. set_timer() takes a long int in order to
interface nicely with libcurl, so use an int32 as the interval counter
and clamp to LONG_MAX during conversion to milliseconds.

Backpatch to 18, where libpq-oauth was introduced.

Reported-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/qtclihmrkq67ach3xjxyi4qcksstin5qxwsnkqefkmotxwh4g6%40ae2bj6jvcmry
Backpatch-through: 18
2026-07-31 11:19:44 -07:00
Jacob Champion
fff8c86759 oauth: Add unit tests for multiplexer handling
(This is a late cherry-pick of 4e1e41733, now that the new suite has
proven its stability, to ensure coverage for this code in PG18 as the
later branches diverge.)

To better record the internal behaviors of oauth-curl.c, add a unit test
suite for the socket and timer handling code. This is all based on TAP
and driven by our existing Test::More infrastructure.

This commit is a replay of 1443b6c0e, which was reverted due to
buildfarm failures. Compared with that, this version protects the build
targets in the Makefile with a with_libcurl conditional, and it tweaks
the code style in 001_oauth.pl.

Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>
Discussion: https://postgr.es/m/CAOYmi+nDZxJHaWj9_jRSyf8uMToCADAmOfJEggsKW-kY7aUwHA@mail.gmail.com
Discussion: https://postgr.es/m/CAOYmi+m=xY0P_uAzAP_884uF-GhQ3wrineGwc9AEnb6fYxVqVQ@mail.gmail.com
2026-07-31 11:19:37 -07:00
Robert Haas
18f0de6b88 Prevent walsummarizer from getting stuck at a timeline switch.
As previously coded, walsummarizer only wants to read WAL from a file
where the TimeLineID in the filename exactly matches the TimeLineID being
summarized. But in some cases, when a timeline switch occurs, the WAL file
from the old timeline is not archived, because it's never completely
filled, so the only way to obtain the contents of that last partial
segment is to read from the first segment on the new timeline. Teach
WAL summarizer to do that, and add a test case to make sure that it
works.

Reported-by: Nick Ivanov <nick.ivanov@enterprisedb.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Tested-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Reviewed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
Reviewed-by: Thom Brown <thom@linux.com>
Discussion: http://postgr.es/m/CA+Tgmobr27GpKDZx3_ezW2+C5_g18i+jSK3sGF_cR-_ESv5N5A@mail.gmail.com
Backpatch-through: 17
2026-07-31 11:57:07 -04:00
Nathan Bossart
4cc49cb703 Fix autovacuum's database sorting.
When db_comparator() was updated to use pg_cmp_s32(), the arguments
were listed in the wrong order.  This caused autovacuum to sort the
databases by their scores in ascending order instead of descending
order.  To fix, swap the arguments to pg_cmp_s32().

Oversight in commit 3b42bdb471.

Reported-by: Хамидуллин Рустам <r.khamidullin@postgrespro.ru>
Author: Хамидуллин Рустам <r.khamidullin@postgrespro.ru>
Discussion: https://postgr.es/m/5c5a7984-b149-b505-7ad9-2a7766c65b55%40postgrespro.ru
Backpatch-through: 17
2026-07-31 10:34:40 -05:00
David Rowley
f70acc8a2b Fix Hash Join performance issue when hashing NULL values
adf97c156 allowed expression evaluation to perform hashing, and
subsequently 9ca67658d fixed a memory stomping bug in that commit
that caused unrelated-to-hashing expression op steps to stomp on the
intermediate hash value.  The intermediate hash value needs to be
maintained when hashing multiple hash keys.  9ca67658d didn't quite get
things right when in "strict" mode when it aborted hashing early after
encountering a NULL hash key.  What was meant to happen was that the
expression returns NULL directly to indicate to the caller the value
hashed to NULL.  The problem was that any EEOP_HASHDATUM_FIRST_STRICT or
EEOP_HASHDATUM_NEXT32_STRICT op step that didn't belong to the final
key to be hashed would have its op->resnull and op->resvalue pointing to
the location to store the intermediate hash value.  That's correct for
non-NULLs since we bit-rotate the intermediate value and continue hashing,
but with the strict case, when we get a NULL key, we immediately jump to
the "jumpdone" step.  The problem is the jumpdone step expects the
ExprState resnull and resvalue fields to be set (as they would be if we
didn't abort hashing early due to the NULL), but when we aborted early,
the ExprState fields never got set.  This would result in inserting
records into the hash table that would never match to any join partner,
which is a waste of CPU and memory.

Here we fix this by having EEOP_HASHDATUM_FIRST_STRICT and
EEOP_HASHDATUM_NEXT32_STRICT populate the ExprState resnull and resvalue
fields directly when the value to hash is NULL.

Although Hash Agg and Hashed Subplans do use hashing from ExprStates,
those were unaffected by this bug, as neither of those uses the STRICT op
steps.

Thanks to Tomas Vondra for finding the offending commit.

Reported-by: Dan Stefura <dstefura@bluecatnetworks.com>
Author: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/YQBPR0101MB89738FB972FBD02A3640C6D3D6C92@YQBPR0101MB8973.CANPRD01.PROD.OUTLOOK.COM
Backpatch-through: 18
2026-07-31 23:24:46 +12:00
David Rowley
02e69be47c Fix issue with RANGE's DEFAULT partition pruning
Partition pruning for RANGE-partitioned tables could mistakenly prune
the DEFAULT partition in some cases when it was not valid to do so,
which could lead to rows missing from query results.

The only known cases where this could happen is when combining pruning
steps from an IS NOT NULL clause with other steps that matched to the
DEFAULT partition.  This could occur due to RANGE partitioned tables
having two distinct internal representations for marking if the DEFAULT
partition should be scanned.  The IS NOT NULL steps would mark the
"scan_default" boolean, but other steps created for different purposes
could mark a bound_offset Bitmapset, which would ultimately translate into
also scanning the default partition.  This could all fail after multiple
steps were combined with a combine intersect operator, as that will
intersect the bound_offset bits and only set scan_default if all pruning
steps have that flag set.  When both input steps to the intersect operator
had different representations of whether to scan the DEFAULT partition,
the resulting intersect step result would contain neither representation.

Here, we fix this by having the IS NOT NULL pruning result mark the
bound_offsets so that it uses both representations to mark that the
DEFAULT partition must be scanned.

Reported-by: Jacob Brazeal <jacob.brazeal@gmail.com>
Diagnosed-by: Jacob Brazeal <jacob.brazeal@gmail.com>
Author: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/CA+COZaDXrfTaBjLE=Z79MTaH6Xun1V4PeKxLvCNv8mXS8wn0rw@mail.gmail.com
Backpatch-through: 14
2026-07-31 15:37:42 +12:00
Tomas Vondra
a0369dd844 Reject non-finite reltuples when restoring stats
When restoring relation stats, pg_restore_relation_stats() rejected
calls with (reltuples < -1.0). But that is insufficient - Infinity and
NaN values both pass that check, and get stored in pg_class verbatim.
This can have various undesirable consequences.

Fixed by rejecting non-finite reltuple values, in the same non-fatal way
as for the existing checks (emit WARNING and skip the update). Adds a
regression test to stats_import for these non-finite values, and to
check the -1.0 special value is still accepted.

Backpatch to 18, where pg_restore_relation_stats() was introduced.

Patch by Jan Nidzwetzki, minor commit message tweaks by me.

Author: Jan Nidzwetzki <jan@planetscale.com>
Discussion: https://postgr.es/m/518BA772-8026-412A-AA8F-A7FE4C6B3717@planetscale.com
Backpatch-through: 18
2026-07-30 16:35:04 +02:00