Stamp 17.11.
commit : 083ac033419f690758508e08c1736089384bbee8
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 16:54:09 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 16:54:09 -0400 M configure
M configure.ac
M meson.build
Update .abi-compliance-history for security fixes.
commit : 83bb18b714e7b98c243083d2480828331601de23
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 12:35:48 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 12:35:48 -0400 Security: CVE-2026-6470, CVE-2026-6471, CVE-2026-6469 M .abi-compliance-history
Last-minute updates for release notes.
commit : 987fa1d0b425a704a3be43a13af032614d2babf6
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 12:15:10 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 12:15:10 -0400 Security: CVE-2026-6464, CVE-2026-6469, CVE-2026-6470, CVE-2026-6471, CVE-2026-14662, CVE-2026-14663, CVE-2026-14664, CVE-2026-14666, CVE-2026-14668, CVE-2026-14669, CVE-2026-14670, CVE-2026-14671, CVE-2026-14672, CVE-2026-14673, CVE-2026-14676, CVE-2026-14677, CVE-2026-14678, CVE-2026-14679, CVE-2026-14680, CVE-2026-14681, CVE-2026-15741, CVE-2026-15742, CVE-2026-16238, CVE-2026-16239, CVE-2026-16241, CVE-2026-18024, CVE-2026-18408, CVE-2026-19385 M doc/src/sgml/release-17.sgml
psql: Don't do backquote expansion in \unrestrict.
commit : 0bfac9e1f946e098b1f61a642e71bb4844757472
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 This oversight in commit 71ea0d6795 allows a malicious server to
inject shell commands into plain-text dump output that are run at
restore time on the machine running psql. To fix, interpret all
text after \unrestrict until the end of the line as its argument.
Reported-by: Lucas Velgus <velgusgus599@gmail.com>
Reported-by: Filip Janus <fjanus@redhat.com>
Reported-by: Daniel Bakker <daniel@jackds.nl>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Security: CVE-2026-18408
Backpatch-through: 14 M doc/src/sgml/ref/psql-ref.sgml
M src/bin/psql/command.c
M src/bin/psql/t/001_basic.pl
pgcrypto: Add option to revert to prior decryption behavior
commit : 7eed42aa88053ce9319f249fc70a46181c026a4b
author : Jacob Champion <jchampion@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 The previous commit raises an ERROR during PGP operations if OpenSSL
does not support the cipher in use. However, any existing messages
created with faulty encryption will no longer be accessible via
pgp_[sym|pub]_decrypt().
To help users out of this situation, add a new ignore-cipher-failure
option which reverts to the broken behavior during decryption only. A
faulty encryption wrapper, created by an OpenSSL configuration that does
not support the cipher, can then be stripped back off by that same
OpenSSL in order to safely reencrypt it. (Note that when OpenSSL does
support the cipher, corrupted messages will not be decrypted regardless
of the ignore-cipher-failure setting; this is unchanged.)
The new tests add a corrupted Blowfish message for both public- and
symmetric-key decryption, resulting in the following test matrix:
- Blowfish supported, default behavior: fails to decrypt
- Blowfish supported, ignore-cipher-failure: fails to decrypt
- Blowfish unsupported, default behavior: fails to load cipher
- Blowfish unsupported, ignore-cipher-failure: strips faulty encryption
The previous commit's change to the pubkey tests is expanded similarly:
correctly encrypted messages cannot be decrypted by an OpenSSL that does
not support the cipher, regardless of the option's setting, though the
failure mode will change.
Suggested-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Noah Misch <noah@leadboat.com>
Security: CVE-2026-14663
Backpatch-through: 14 M contrib/pgcrypto/expected/pgp-decrypt.out
M contrib/pgcrypto/expected/pgp-decrypt_1.out
M contrib/pgcrypto/expected/pgp-info.out
M contrib/pgcrypto/expected/pgp-pubkey-decrypt.out
M contrib/pgcrypto/expected/pgp-pubkey-decrypt_1.out
M contrib/pgcrypto/pgp-cfb.c
M contrib/pgcrypto/pgp-decrypt.c
M contrib/pgcrypto/pgp-encrypt.c
M contrib/pgcrypto/pgp-pgsql.c
M contrib/pgcrypto/pgp-pubkey.c
M contrib/pgcrypto/pgp.c
M contrib/pgcrypto/pgp.h
M contrib/pgcrypto/sql/pgp-decrypt.sql
M contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql
M doc/src/sgml/pgcrypto.sgml
Fix errorhandling for PGP encryption
commit : b05cfc69375e33277307a99bf1d77462ab929c8a
author : Daniel Gustafsson <dgustafsson@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 PGP encryption was using px_cipher_encrypt without checking if any
error was returned. When OpenSSL is running in FIPS mode, or when
the legacy provider hasn't been loaded, not all ciphers which are
supported by the PGP code are available and fail the init step in
px_cipher_encrypt. Since the PGP encryption failed to notice this
it XORed the non-encrypted block with the plaintext, effectively
disabling the encryption.
This was found due to a report of PGP encryption not respecting
the pgcrypto.builtin_crypto_enabled flag and allowing Blowfish
and DES. This however turned out to be a false positive, since
the PGP code only use ciphers from OpenSSL and not the built in
ciphers.
Bug: #19457
Reported-by: Shishir Sharma <ansh01072001@gmail.com>
Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com>
Discussion: https://postgr.es/m/19457-4bab15c17aea36c7@postgresql.org
Security: CVE-2026-14663
Backpatch-through: 14 M contrib/pgcrypto/expected/pgp-decrypt_1.out
A contrib/pgcrypto/expected/pgp-encrypt_1.out
M contrib/pgcrypto/expected/pgp-pubkey-decrypt_1.out
M contrib/pgcrypto/pgp-cfb.c
Fix out-of-bound reads with ascii() for invalid multibyte characters
commit : 849da82105395fa4d06f877db8edc62158167941
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 This commit addresses two defects in this SQL function, the code
assuming that:
- The user-supplied string was long enough to contain a character of the
length implied by the first byte. It is possible to provide in input
data that was able to disclose a few bytes of server memory, allowing
out-of-bound reads.
- Specific bytes had values within the expected range, using a set of
assertions to validate them. The assertions could be triggered on
invalid input. These are replaced by tests and error reports.
Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Backpatch-through: 14
Security: CVE-2026-18024 M src/backend/utils/adt/oracle_compat.c
M src/test/regress/expected/encoding.out
M src/test/regress/sql/encoding.sql
Teach psql to skip in-line COPY ... FROM STDIN data after a failure.
commit : 46fa1f6f373865fae7553043790cd17944893ac3
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 If the COPY command fails before sending PGRES_COPY_IN, psql did
not realize that it ought to consume any in-line data following
the command. Failing to do so leads to trying to execute that
data as SQL commands, which in the best case is wrong and in the
worst case is a SQL-injection hazard.
To fix:
1. Extend psqlscan.l to recognize COPY ... FROM STDIN. This can
be done with a pretty simple extension to the logic that already
recognizes nested BEGIN blocks within CREATE FUNCTION et al.
But unlike that case, we need to consider and count multiple COPY
commands within a single query string (separated by "\;"). The
fallout from that is that psql_scan_reset must now always be called
before starting a new query string. (The comment for it that claimed
we didn't need that because "the scan state must be INITIAL" was
really obsolete already, since it has long reset more state besides
start_state.)
2. Teach handleCopyIn() to read and discard data when passed
NULL for "conn".
3. Add logic to SendQuery() to call handleCopyIn() that way
if the query string contained COPY ... FROM STDIN command(s)
that remain unaccounted-for at the end.
Now that we have this counting logic, we can also detect
if the backend sends an unexpected PGRES_COPY_IN message.
That should never happen, but perhaps a malicious server
could try to extract data that way.
A side-effect of doing this is that we have to adjust a number of test
scripts that thought they needn't write "\." after a COPY FROM STDIN
that they expect to fail. On the whole this is an improvement, since
there's now a uniform rule "write \. after COPY FROM STDIN, whether
you expect it to work or not". But it is an annoying amount of test
churn.
A loose end in this patch is that if it has to skip data, it assumes
that that data is text not binary. It seems unduly difficult to
detect whether the COPY command requested binary (we could handle the
old-style COPY BINARY ... syntax, but not the new style with format
options). In practice, copying in-line binary data is unsupported
anyway, because there's no way to write an end marker: the textual
terminator sequence "\n\\.\n" could appear in binary data and there's
no provision for escaping it, so neither psql nor the server look for
it when in binary mode.
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-6464 M src/bin/psql/common.c
M src/bin/psql/common.h
M src/bin/psql/copy.c
M src/bin/psql/mainloop.c
M src/bin/psql/psqlscanslash.l
M src/bin/psql/startup.c
M src/fe_utils/psqlscan.l
M src/include/fe_utils/psqlscan.h
M src/include/fe_utils/psqlscan_int.h
M src/test/regress/expected/copy.out
M src/test/regress/expected/psql.out
M src/test/regress/sql/alter_table.sql
M src/test/regress/sql/copy.sql
M src/test/regress/sql/copy2.sql
M src/test/regress/sql/copyselect.sql
M src/test/regress/sql/generated.sql
M src/test/regress/sql/privileges.sql
M src/test/regress/sql/psql.sql
M src/test/regress/sql/rowsecurity.sql
Save/restore more lexer state when skipping text due to \if.
commit : dca6627de0f3b5a5798529b4ad5012a9e9b55f49
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 When we implemented \if ... \endif in psql, we arranged to
save/restore the lexer's parenthesis depth counter across any chunk
of input that we're ignoring. At the time, that was sufficient,
because no other part of PsqlScanState could need to be restored to
its prior value. However, commit e717a9a18 and follow-ons added
more state fields that ought to be restored to their prior values.
A problem would only be observed if someone tries to \if out a
portion of a CREATE FUNCTION/PROCEDURE command that is relevant to
BEGIN/END matching, which seems like a pretty unusual usage, so the
lack of field reports isn't surprising. Nonetheless it's a bug.
To fix, replace the simple counter field in ConditionalStack
entries with a pointer to a struct defined by psqlscan_int.h.
(In the back branches, keep the old field and associated functions
to minimize the risk of API/ABI breakage, even though it seems
unlikely that any third-party code is using this. Making the
new struct private to psqlscan-related code should prevent API/ABI
issues for future additions of this type.)
In itself this is only a minor bug fix, but it's prerequisite
infrastructure for the fix for CVE-2026-6464, which will add
another such field.
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-6464 M src/bin/psql/command.c
M src/bin/psql/psqlscanslash.h
M src/bin/psql/psqlscanslash.l
M src/fe_utils/conditional.c
M src/include/fe_utils/conditional.h
M src/include/fe_utils/psqlscan.h
M src/include/fe_utils/psqlscan_int.h
M src/test/regress/expected/psql.out
M src/test/regress/sql/psql.sql
M src/tools/pgindent/typedefs.list
Invalidate plan cache after role changes.
commit : 1974acf23cb2a5273821162abe68cd2f70fde682
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 Role membership, role attribute, and database ownership changes may
impact the expected behavior of row-level security policies, but
currently the plan cache doesn't take notice. To fix, register
syscache callbacks on pg_auth_members, pg_authid, and pg_database
that invalidate the role-dependent plans. Changes to other
databases' pg_database rows are ignored.
Reported-by: Ilya Staroverov <i.staroverov@ftdata.ru>
Reported-by: Shinya Kato <shinya11.kato@gmail.com>
Author: Ilya Staroverov <i.staroverov@ftdata.ru>
Author: Shinya Kato <shinya11.kato@gmail.com>
Co-authored-by: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Security: CVE-2026-14666
Backpatch-through: 14 M src/backend/utils/adt/acl.c
M src/backend/utils/cache/plancache.c
M src/include/utils/acl.h
Check for USAGE privilege on the composite type in ALTER TABLE OF.
commit : 67135960559d5e623757ffa8ec0ab4d94293dfc2
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 This omission allowed roles without USAGE on a type to create
tables that depend on it, which could prevent the owner from
changing the type later.
Reported-by: Nathan Bossart <nathandbossart@gmail.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Security: CVE-2026-6470
Backpatch-through: 14 M src/backend/commands/tablecmds.c
M src/test/regress/expected/privileges.out
M src/test/regress/sql/privileges.sql
Check for USAGE privilege on types used by stored expressions.
commit : d1c8aa0b09f18bba1343ce2e4aa537a17a8a972f
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 This omission allowed roles without USAGE on a type to create
stored expressions that depend on it, which could prevent the owner
from changing the type later.
The checks deliberately live in the command paths rather than the
dependency-recording routines. Those routines also run whenever
the server re-derives an existing expression, and re-checking there
would break routine maintenance for an owner who has since lost
USAGE on a type its objects already reference. (Checking in the
dependency-recording routines would also require additional
CommandCounterIncrement() calls to avoid spurious errors.)
The addition of a parameter to AlterDomainAddConstraint() breaks
ABI compatibility, but we are unaware of any impacted third-party
code.
Reported-by: Noah Misch <noah@leadboat.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Security: CVE-2026-6470
Backpatch-through: 14 M src/backend/catalog/dependency.c
M src/backend/catalog/heap.c
M src/backend/catalog/index.c
M src/backend/catalog/pg_attrdef.c
M src/backend/catalog/pg_constraint.c
M src/backend/catalog/pg_proc.c
M src/backend/catalog/pg_publication.c
M src/backend/catalog/pg_type.c
M src/backend/commands/indexcmds.c
M src/backend/commands/policy.c
M src/backend/commands/statscmds.c
M src/backend/commands/tablecmds.c
M src/backend/commands/trigger.c
M src/backend/commands/typecmds.c
M src/backend/parser/parse_utilcmd.c
M src/backend/rewrite/rewriteDefine.c
M src/backend/tcop/utility.c
M src/include/catalog/dependency.h
M src/include/commands/typecmds.h
M src/test/regress/expected/privileges.out
M src/test/regress/sql/privileges.sql
Check for USAGE privilege on the subtype in CREATE TYPE AS RANGE.
commit : fd6d3e7e9d5554bd11623d11445d82c7293e36e2
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 This omission allowed roles without USAGE on a type to create range
types that depend on it, which could prevent the owner from
changing the type later.
Reported-by: Jingzhou Fu <fuboat@outlook.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Security: CVE-2026-6470
Backpatch-through: 14 M doc/src/sgml/ref/create_type.sgml
M src/backend/commands/typecmds.c
M src/test/regress/expected/rangetypes.out
M src/test/regress/sql/rangetypes.sql
Avoid overflow in Levenshtein distance calculations.
commit : c4d51b62748fd697e5ef4c1108dc77396ba39475
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:19 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:19 -0700 levenshtein() and levenshtein_less_equal() let the caller specify
the insertion, deletion, and substitution costs, and
fuzzystrmatch's corresponding SQL functions accept any 32-bit
integer for each. Since the distances are calculated with 32-bit
arithmetic, large costs can cause overflows, thereby producing
nonsensical results. Certain inputs to levenshtein_less_equal()
can even cause out-of-bounds writes. To fix, use 64-bit arithmetic
instead, and error whenever the final result won't fit in the
returned 32-bit integer.
We may want to teach these functions to reject negative costs, too,
but that didn't seem appropriate for a security fix, and therefore
it 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: Dean Rasheed <dean.a.rasheed@gmail.com>
Security: CVE-2026-15742
Backpatch-through: 14 M contrib/fuzzystrmatch/expected/fuzzystrmatch.out
M contrib/fuzzystrmatch/sql/fuzzystrmatch.sql
M src/backend/utils/adt/levenshtein.c
M src/backend/utils/adt/varlena.c
Cross-check the type of a portal running EXECUTE or FETCH.
commit : 60887d34818a517ee7a21ef4f7eb18d03e7d1f4a
author : Robert Haas <rhaas@postgresql.org>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 When an EXECUTE or FETCH statement is executed, there are two portals:
an outer portal that is created for the EXECUTE or FETCH statement itself,
and an inner portal for the statement being executed on its behalf.
Before this commit, nothing checked that these two portals agreed on
the tuple descriptor of the rows being returned. This can be leveraged
to disclose server memory contents and achieve arbitrary code execution.
To prevent that, we can make use of an existing safety mechanism,
added by Tom Lane in commit 2f48ede080f42b97b594fb14102c82ca1001b80c,
which allows a tuplestore DestReceiver to be informed of the tupleDesc
required by the caller, and which will cause an ERROR to occur if
that doesn't match the tupleDesc of what emerges from the executor
(modulo dropped columns, which aren't an issue in the case at hand).
Reported-by: Ben Morris in collaboration with Claude and Anthropic Research
Reported-by: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Security: CVE-2026-16239 M src/backend/tcop/pquery.c
Add an output_plugin_libraries GUC to bless trusted output plugins
commit : 01992176e08169b7aedf2d61be9e22518b5c6640
author : Jacob Champion <jchampion@postgresql.org>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 REPLICATION users were not previously subject to restrictions on output
plugin paths, so they were able to bypass LOAD-time protections during
logical decoding. Unfortunately, adding the standard LOAD restrictions
now would retroactively require all third-party output plugins to be
installed under the $libdir/plugins directory. This would prevent the
use of dynamic_library_path, introduce a wire incompatibility for
clients, and require all plugin authors to check that their libraries
are safe for use by any unprivileged user; we want to avoid that.
Instead, introduce an output_plugin_libraries GUC so that DBAs can
specify the output plugins that are trusted for use in logical decoding.
For simplicity, superusers are subject to the restriction as well
(though they're free to modify the GUC at will during a session, so no
power is actually lost).
The default setting is 'pgoutput, test_decoding'. If other third-party
plugins are in use, DBAs will need to modify this parameter after they
update. Some pointers have been added to the documentation to assist
with this.
Author: Jacob Champion <jacob.champion@enterprisedb.com>
Reported-by: Vladimir Tokarev <vladimirelitokarev@gmail.com>
Reported-by: Yu Kunpeng <yu443940816@live.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-6471 M contrib/test_decoding/expected/permissions.out
M contrib/test_decoding/expected/slot.out
M contrib/test_decoding/sql/permissions.sql
M contrib/test_decoding/sql/slot.sql
M doc/src/sgml/config.sgml
M doc/src/sgml/logical-replication.sgml
M doc/src/sgml/ref/pgupgrade.sgml
M src/backend/replication/logical/logical.c
M src/backend/utils/misc/guc_tables.c
M src/backend/utils/misc/postgresql.conf.sample
M src/bin/pg_dump/dumputils.c
M src/bin/pg_upgrade/check.c
M src/bin/pg_upgrade/t/003_logical_slots.pl
M src/include/replication/logical.h
M src/test/subscription/t/100_bugs.pl
Move SplitGUCList() to fe_utils
commit : 4fcccea972bcdce66976da86535e970dea9b999f
author : Jacob Champion <jchampion@postgresql.org>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 This is needed so that all versions of pg_upgrade that migrate logical
replication slots can parse the new output_plugin_libraries GUC.
Backpatch-through: 17
Security: CVE-2026-6471 M src/backend/utils/adt/varlena.c
M src/bin/pg_dump/dumputils.c
M src/bin/pg_dump/dumputils.h
M src/fe_utils/string_utils.c
M src/include/fe_utils/string_utils.h
Empty search_path in amcheck.
commit : e41c72aff0399dd46f3c4f2f7ee242e99ecf0e32
author : Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 A grantee of amcheck function EXECUTE privilege could execute arbitrary
functions as the owners of expression indexes that depend on the search
path. An expression like (lower(col)) was not vulnerable, because
lower() is resolved at CREATE INDEX time. However, an expression
calling an sql-language or plpgsql-language function often was
vulnerable, even if it used search_path only to find objects in
pg_catalog. The amcheck documentation has been warning about data
disclosure after such a GRANT, not about function execution.
This might cause new amcheck errors when index expressions rely on a
broader search_path. Such indexes have seen errors during auto-analyze
since CVE-2018-1058 commit 582edc369cdbd348d68441fc50fa26a84afd0c1a, and
v17 amcheck always worked this way. Hence, the risk is low.
Leave a comment on the one other sandbox entrance that doesn't empty
search_path. In its case, the choice was valid.
Back-patch to v14 (all supported versions), but v17 was safe already.
Commit 2af07e2f749a9208ca1ed84fa1d8fe0e75833288 (v17) unintentionally
blocked the attack, and commit d70b17636ddf1ea2c71d1c7bc477372b36ccb66b
(v18) unintentionally removed that protection. Hence, this adds to v17
just a test and a comment. While emptying search_path became more
widespread in commit 2af07e2f749a9208ca1ed84fa1d8fe0e75833288 (v17),
none of its other changes blocked an attack available in v16, even when
considering GRANT. For example, brin_summarize_range() has had an owner
check that GRANT does not override.
Reported-by: 王跃林 <violin0613@tju.edu.cn>
Reported-by: Jacob Brazeal <jacob.brazeal@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14673 M contrib/amcheck/expected/check_btree.out
M contrib/amcheck/sql/check_btree.sql
M src/backend/utils/init/usercontext.c
Use value of scram_iterations in mock_scram_secret().
commit : dec60e8ada4cd46d0201efea844a4b22cb06444e
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 Presently, mock_scram_secret() always uses
SCRAM_SHA_256_DEFAULT_ITERATIONS, which poses an observable
response discrepancy hazard when scram_iterations is set to
something else. To fix, use the value of the configuration
parameter instead, and document that unauthenticated users can
discover the existence of roles with passwords created with
different iteration counts.
Reported-by: Radim Marek <radim@boringsql.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Reviewed-by: Jacob Champion <champion.p@gmail.com>
Security: CVE-2026-14672
Backpatch-through: 16 M doc/src/sgml/config.sgml
M src/backend/libpq/auth-scram.c
Obstruct EXTRACT() field name deparse injection.
commit : 5981fe370a0d433429977ff6fc420064cf2fa09a
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 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 M src/backend/utils/adt/ruleutils.c
Reject GSSEncRequest after direct SSL connection
commit : 067a64d40f92e4e012db0367f9ff2d2ae45671ca
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 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 M src/backend/tcop/backend_startup.c
ecpg: Fix out-of-bound writes due to processing of invalid bytea data
commit : c3c830272a97b9b429eb015c2df206264649c6fc
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 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 M src/interfaces/ecpg/ecpglib/data.c
M src/interfaces/ecpg/ecpglib/error.c
M src/interfaces/ecpg/include/ecpgerrno.h
M src/interfaces/ecpg/test/expected/sql-bytea.c
M src/interfaces/ecpg/test/expected/sql-bytea.stderr
M src/interfaces/ecpg/test/sql/bytea.pgc
Use palloc_array() in pltcl and plperl to avoid overflow
commit : b56cc7deb9af972226f7d6259248e00eb124069f
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 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 M src/pl/plperl/SPI.xs
M src/pl/plperl/plperl.c
M src/pl/tcl/pltcl.c
Fix pg_trgm's picksplit function with all-true datums
commit : 1af08af694815520e5642dc3a85cc010cbcf9f84
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 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 M contrib/pg_trgm/trgm_gist.c
Preserve the owner of extended statistics rebuilt by ALTER TABLE.
commit : 75a03c569c761fa27ba15975f342b72ab0d28946
author : Masahiko Sawada <msawada@postgresql.org>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 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 M src/backend/commands/statscmds.c
M src/backend/commands/tablecmds.c
M src/backend/tcop/utility.c
M src/include/commands/defrem.h
M src/include/nodes/parsenodes.h
M src/test/regress/expected/stats_ext.out
M src/test/regress/sql/stats_ext.sql
Return nulls honestly in aggregate "combine" functions.
commit : 83d0a083f178f22c60814b93d17ecacdcce76eac
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:18 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:18 -0700 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 M src/backend/utils/adt/numeric.c
M src/backend/utils/adt/timestamp.c
Reject calls from SQL to functions that take or return type internal.
commit : eb9e5529745c129c25deb04098612898998fb123
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/parser/parse_coerce.c
M src/backend/parser/parse_func.c
M src/backend/parser/parse_oper.c
M src/pl/plpgsql/src/pl_exec.c
Protect some fixed-size arrays that have FUNC_MAX_ARGS elements.
commit : 8a40f4b092987f735e712b789d8acbe3b3af8274
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/executor/nodeWindowAgg.c
M src/backend/parser/parse_agg.c
M src/backend/parser/parse_func.c
M src/backend/utils/fmgr/funcapi.c
M src/pl/plpgsql/src/pl_comp.c
M src/pl/tcl/pltcl.c
pg_dump: avoid assuming how long pg_proc.protrftypes can be.
commit : c2b16f5d495d977d669c7ec5db07bb666f3691e7
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/bin/pg_dump/common.c
M src/bin/pg_dump/pg_dump.c
M src/bin/pg_dump/pg_dump.h
M src/test/regress/expected/object_address.out
M src/test/regress/sql/object_address.sql
Replace fixed-size, too-short array with a palloc'd one.
commit : 797e3cc4c41b70eea75f4063713988c09edf6007
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/catalog/namespace.c
Be more wary about constant's datatype in scalarineqsel().
commit : 0ebf896f44d2a930c7e3722621e319a3d923c830
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/utils/adt/selfuncs.c
Harden PL/Perl code against "tied" Perl arrays and hashes.
commit : 2d78c34f8257d00f5fc65b8092c43dc77e246939
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M contrib/hstore_plperl/hstore_plperl.c
M src/pl/plperl/plperl.c
Fix potential buffer overrun in regexp match/split functions.
commit : e91dcfccaaa827f2907307e12891eeb131629948
author : Masahiko Sawada <msawada@postgresql.org>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/utils/adt/regexp.c
Harden tsquery code against overflows.
commit : 8e87bd4731d7d285b1d06bead0e74058bdb82a69
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/utils/adt/tsquery_util.c
M src/include/tsearch/ts_type.h
Harden tsvector code against overflows.
commit : fe0b5bd6dedc23278f1a48bb3422833e936d881e
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/tsearch/to_tsany.c
M src/backend/tsearch/ts_parse.c
M src/backend/utils/adt/tsvector.c
M src/backend/utils/adt/tsvector_op.c
M src/include/tsearch/ts_type.h
Guard against overlength time zone abbreviations in to_char().
commit : 12a6206864a0ba38dc506644bdb3928beea5256a
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 10 Aug 2026 06:38:17 -0700
committer: Noah Misch <noah@leadboat.com>
date : Mon, 10 Aug 2026 06:38:17 -0700 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 M src/backend/utils/adt/formatting.c
Translation updates
commit : 3e85b223b0664cb9bee80cde786d778c1f705d63
author : Peter Eisentraut <peter@eisentraut.org>
date : Mon, 10 Aug 2026 12:17:04 +0200
committer: Peter Eisentraut <peter@eisentraut.org>
date : Mon, 10 Aug 2026 12:17:04 +0200 Source-Git-URL: https://git.postgresql.org/git/pgtranslation/messages.git
Source-Git-Hash: e2e72c73155c6ef2002c25be726c102fd8243740 M src/backend/po/de.po
M src/backend/po/ja.po
M src/backend/po/ru.po
M src/bin/initdb/po/de.po
M src/bin/initdb/po/ja.po
M src/bin/initdb/po/ru.po
M src/bin/pg_amcheck/po/de.po
M src/bin/pg_amcheck/po/ru.po
M src/bin/pg_archivecleanup/po/de.po
M src/bin/pg_archivecleanup/po/ru.po
M src/bin/pg_basebackup/po/de.po
M src/bin/pg_basebackup/po/ja.po
M src/bin/pg_basebackup/po/ru.po
M src/bin/pg_checksums/po/de.po
M src/bin/pg_checksums/po/ru.po
M src/bin/pg_combinebackup/po/de.po
M src/bin/pg_combinebackup/po/ja.po
M src/bin/pg_combinebackup/po/ru.po
M src/bin/pg_config/po/de.po
M src/bin/pg_config/po/ru.po
M src/bin/pg_controldata/po/de.po
M src/bin/pg_controldata/po/ru.po
M src/bin/pg_ctl/po/de.po
M src/bin/pg_ctl/po/ja.po
M src/bin/pg_ctl/po/ru.po
M src/bin/pg_dump/po/de.po
M src/bin/pg_dump/po/ja.po
M src/bin/pg_dump/po/ru.po
M src/bin/pg_resetwal/po/de.po
M src/bin/pg_resetwal/po/ru.po
M src/bin/pg_rewind/po/de.po
M src/bin/pg_rewind/po/ja.po
M src/bin/pg_rewind/po/ru.po
M src/bin/pg_test_fsync/po/de.po
M src/bin/pg_test_fsync/po/ru.po
M src/bin/pg_test_timing/po/de.po
M src/bin/pg_test_timing/po/ja.po
M src/bin/pg_test_timing/po/ru.po
M src/bin/pg_upgrade/po/de.po
M src/bin/pg_upgrade/po/ru.po
M src/bin/pg_verifybackup/po/de.po
M src/bin/pg_verifybackup/po/ru.po
M src/bin/pg_waldump/po/de.po
M src/bin/pg_waldump/po/ru.po
M src/bin/pg_walsummary/po/de.po
M src/bin/pg_walsummary/po/ru.po
M src/bin/psql/po/de.po
M src/bin/psql/po/ru.po
M src/bin/scripts/po/de.po
M src/bin/scripts/po/ru.po
M src/interfaces/ecpg/preproc/po/ru.po
M src/interfaces/libpq/po/de.po
M src/interfaces/libpq/po/ja.po
M src/interfaces/libpq/po/ru.po
M src/pl/plpython/po/de.po
M src/pl/plpython/po/ja.po
M src/pl/plpython/po/ru.po
Release notes for 18.5, 17.11, 16.15, 15.19, 14.24.
commit : 6edf76ee3d4969ab6ca9c63ba3f7da2049fbd479
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 9 Aug 2026 12:52:47 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 9 Aug 2026 12:52:47 -0400 M doc/src/sgml/release-17.sgml
Drain pending asynchronous requests during ExecReScanAppend.
commit : 3704870b29c5f3d662a30ab242a2b50e6354b944
author : Etsuro Fujita <efujita@postgresql.org>
date : Fri, 7 Aug 2026 17:30:03 +0900
committer: Etsuro Fujita <efujita@postgresql.org>
date : Fri, 7 Aug 2026 17:30:03 +0900 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 M contrib/postgres_fdw/expected/postgres_fdw.out
M contrib/postgres_fdw/postgres_fdw.c
M contrib/postgres_fdw/sql/postgres_fdw.sql
M src/backend/executor/nodeAppend.c
Fix local pgstat entry leak on OOM during entry creation
commit : fc9283b21535615486ed476e01145ad3d5617973
author : Michael Paquier <michael@paquier.xyz>
date : Fri, 7 Aug 2026 14:23:36 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Fri, 7 Aug 2026 14:23:36 +0900 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 8191e0c16a03.
Author: Niall Newman <nn@turacolabs.com>
Discussion: https://postgr.es/m/2FDAA194-9CF3-4FD7-A450-F1A4BEB125F6@turacolabs.com
Backpatch-through: 15 M src/backend/utils/activity/pgstat_shmem.c
Fix race condition in subscription TAP test 023_twophase_stream.
commit : 3df129b8d7217e50e7dfbc501c0e00e46320fabd
author : Amit Kapila <akapila@postgresql.org>
date : Thu, 6 Aug 2026 11:20:26 +0530
committer: Amit Kapila <akapila@postgresql.org>
date : Thu, 6 Aug 2026 11:20:26 +0530 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 M src/test/subscription/t/023_twophase_stream.pl
Fix calculating length of match to localized month/weekday names
commit : 8acfaa12a4c795304c623bf62e7e07693ec14f50
author : Álvaro Herrera <alvherre@kurilemu.de>
date : Wed, 5 Aug 2026 11:40:39 +0200
committer: Álvaro Herrera <alvherre@kurilemu.de>
date : Wed, 5 Aug 2026 11:40:39 +0200 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> M src/backend/utils/adt/formatting.c
M src/test/regress/expected/collate.linux.utf8.out
M src/test/regress/sql/collate.linux.utf8.sql
doc: Update XID wraparound error example
commit : 9484169ba070e1a7fe5b9b1d7a5f6035a37af0a3
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 5 Aug 2026 11:36:43 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 5 Aug 2026 11:36:43 +0900 Commit edee0c621de, and the equivalent v17 commit f2353dd71724,
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 M doc/src/sgml/maintenance.sgml
pg_surgery: Fix infinite loop on large TID arrays
commit : 1b6c99d96a9302d3aca7ef900e173a889e9700f9
author : Álvaro Herrera <alvherre@kurilemu.de>
date : Tue, 4 Aug 2026 11:44:11 +0200
committer: Álvaro Herrera <alvherre@kurilemu.de>
date : Tue, 4 Aug 2026 11:44:11 +0200 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 M contrib/pg_surgery/expected/heap_surgery.out
M contrib/pg_surgery/heap_surgery.c
M contrib/pg_surgery/sql/heap_surgery.sql
Fix ALTER COLUMN ... DROP EXPRESSION with subpartitions
commit : 18006c1bd664e9d6b2f202131ba3b50c90600629
author : Álvaro Herrera <alvherre@kurilemu.de>
date : Tue, 4 Aug 2026 09:06:46 +0200
committer: Álvaro Herrera <alvherre@kurilemu.de>
date : Tue, 4 Aug 2026 09:06:46 +0200 Per commit 8bf6ec3ba3a4, 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
8bf6ec3ba3a4 explains.
Author: Alberto Piai <alberto.piai@gmail.com>
Backpatch-through: 14
Discussion: https://postgr.es/m/DHMT78XOD8BK.341V3H87KZ7NO@gmail.com M src/backend/commands/tablecmds.c
M src/test/regress/expected/generated.out
M src/test/regress/sql/generated.sql
Fix missing money overflow checks for INT64_MIN / -1
commit : 1416f304d2c9514fe65f112514accc9b653902ad
author : David Rowley <drowley@postgresql.org>
date : Tue, 4 Aug 2026 18:00:49 +1200
committer: David Rowley <drowley@postgresql.org>
date : Tue, 4 Aug 2026 18:00:49 +1200 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 M src/backend/utils/adt/cash.c
M src/test/regress/expected/money.out
M src/test/regress/sql/money.sql
Fix missing MCXT_ALLOC_NO_OOM handling in MemoryContextAllocAligned
commit : cce758797f75c19080801ddad213f46d7900ec2b
author : David Rowley <drowley@postgresql.org>
date : Tue, 4 Aug 2026 16:10:18 +1200
committer: David Rowley <drowley@postgresql.org>
date : Tue, 4 Aug 2026 16:10:18 +1200 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 M src/backend/utils/mmgr/mcxt.c
Fix lock release for role membership grants in DROP OWNED BY.
commit : 25e54cec72ae30809a2fdf6fdf2b1f726bd9142a
author : Jeff Davis <jdavis@postgresql.org>
date : Mon, 3 Aug 2026 12:21:05 -0700
committer: Jeff Davis <jdavis@postgresql.org>
date : Mon, 3 Aug 2026 12:21:05 -0700 Commit 6566133c5f5 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 M src/backend/catalog/dependency.c
A src/test/isolation/expected/drop-owned-grant.out
M src/test/isolation/isolation_schedule
A src/test/isolation/specs/drop-owned-grant.spec
Do not log subscription conninfo.
commit : a961b102cd96be2b8f1bad385607e8e7d9deb774
author : Jeff Davis <jdavis@postgresql.org>
date : Mon, 3 Aug 2026 11:34:58 -0700
committer: Jeff Davis <jdavis@postgresql.org>
date : Mon, 3 Aug 2026 11:34:58 -0700 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 M src/backend/replication/logical/worker.c
Tighten up TS dictionary cache entry creation.
commit : 634a8dcb8f64bed1a74a465c707ee25cb6178fea
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 2 Aug 2026 16:49:18 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 2 Aug 2026 16:49:18 -0400 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 M src/backend/utils/cache/ts_cache.c
Fix memory-safety bugs in the ispell/hunspell dictionary loader.
commit : 5fdea3aa321b6899b5e392b7dc159809726ad7d4
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 2 Aug 2026 13:22:39 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 2 Aug 2026 13:22:39 -0400 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 M src/backend/tsearch/spell.c
Update time zone data files to tzdata release 2026c.
commit : 669438aed4c91746e58feb9f4b0620f9bbc1189c
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 2 Aug 2026 11:26:30 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 2 Aug 2026 11:26:30 -0400 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 M src/timezone/data/tzdata.zi
Prevent walsummarizer from getting stuck at a timeline switch.
commit : 499d9eabb5698ff6091b5a186acd7d05cf9d4c2b
author : Robert Haas <rhaas@postgresql.org>
date : Fri, 31 Jul 2026 11:57:44 -0400
committer: Robert Haas <rhaas@postgresql.org>
date : Fri, 31 Jul 2026 11:57:44 -0400 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 M src/backend/postmaster/walsummarizer.c
M src/bin/pg_walsummary/meson.build
A src/bin/pg_walsummary/t/003_tli_switch.pl
Fix autovacuum's database sorting.
commit : 288d4e83f1dab9fc9744eed7129e4f77d82be7ad
author : Nathan Bossart <nathan@postgresql.org>
date : Fri, 31 Jul 2026 10:34:40 -0500
committer: Nathan Bossart <nathan@postgresql.org>
date : Fri, 31 Jul 2026 10:34:40 -0500 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 M src/backend/postmaster/autovacuum.c
Fix issue with RANGE's DEFAULT partition pruning
commit : 31f2acde53d2b8c289614dcf47d40cad8daf7750
author : David Rowley <drowley@postgresql.org>
date : Fri, 31 Jul 2026 15:38:10 +1200
committer: David Rowley <drowley@postgresql.org>
date : Fri, 31 Jul 2026 15:38:10 +1200 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 M src/backend/partitioning/partprune.c
M src/test/regress/expected/partition_prune.out
M src/test/regress/sql/partition_prune.sql
Skip SUBSCRIPTION TABLE TOC entries with --no-subscriptions.
commit : 41f1cd1d2636003749b3197cec057fdf974491f6
author : Amit Kapila <akapila@postgresql.org>
date : Thu, 30 Jul 2026 11:18:39 +0530
committer: Amit Kapila <akapila@postgresql.org>
date : Thu, 30 Jul 2026 11:18:39 +0530 pg_dump in --binary-upgrade mode emits "SUBSCRIPTION TABLE" TOC entries to
preserve pg_subscription_rel state across pg_upgrade. When such a dump
was restored with --no-subscriptions, _tocEntryRequired() skipped the
"SUBSCRIPTION" entry but not the associated "SUBSCRIPTION TABLE" entries,
so the restore would try to apply subscription-relation state for a
subscription that was never created.
Skip "SUBSCRIPTION TABLE" entries as well when no_subscriptions is set.
This can happen when pg_subscription_rel has entries, the dump is taken
with --binary-upgrade, and it is restored with --no-subscriptions.
Reported-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Author: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Shlok Kyal <shlok.kyal.oss@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 17, where it was introduced
Discussion: https://postgr.es/m/OS9PR01MB121493DA4C1A7748B11A646D8F5C02@OS9PR01MB12149.jpnprd01.prod.outlook.com M src/bin/pg_dump/pg_backup_archiver.c
doc: Add a note that refint will be removed in v20
commit : e1885a875cbc5662c53dcafb26f31a35adb66a8a
author : Daniel Gustafsson <dgustafsson@postgresql.org>
date : Wed, 29 Jul 2026 21:51:46 +0200
committer: Daniel Gustafsson <dgustafsson@postgresql.org>
date : Wed, 29 Jul 2026 21:51:46 +0200 refint has been removed from the spi contrib module in v20. Add a note
to the documentation of the still-supported back branches so that users
are aware the module is going away.
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reported-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CAJTYsWUHq8Ohc6-N-xamOPYz-q3qUYMtwQX-1=Zi=5N1Q_GSEQ@mail.gmail.com
Backpatch-through: 14 M doc/src/sgml/contrib-spi.sgml
Fix cascading standby reconnect failure after archive fallback
commit : 2cf28d1b9a273ba5627a04066746726bf3e54662
author : Álvaro Herrera <alvherre@kurilemu.de>
date : Wed, 29 Jul 2026 17:15:45 +0200
committer: Álvaro Herrera <alvherre@kurilemu.de>
date : Wed, 29 Jul 2026 17:15:45 +0200 A cascading standby could fail to reconnect to its upstream standby with
"requested starting point ... is ahead of the WAL flush position" after
falling back to archive recovery. This happened because archive
recovery processes whole segment files, so after replaying a segment the
cascade's next read position lands at the start of the following
segment, which is ahead of the upstream's flush position reported by
GetStandbyFlushRecPtr() (still inside the just-replayed segment).
Fix by having the walreceiver check the upstream's current WAL flush
position via IDENTIFY_SYSTEM before issuing START_REPLICATION.
IDENTIFY_SYSTEM already returns this position (as xlogpos), but
walrcv_identify_system() previously discarded it; now we have a use for
it. If the requested start point exceeds the upstream's flush position
on the same timeline, the walreceiver waits for
wal_retrieve_retry_interval and retries.
The wait is limited to gaps of at most one WAL segment, which is the
expected case from the segment-granularity of archive recovery. Larger
gaps indicate the upstream is genuinely behind, so START_REPLICATION is
allowed to proceed (and fail) normally, letting the startup process fall
back to other WAL sources. The first wait is logged at LOG level;
subsequent waits are demoted to DEBUG1 to avoid log noise. The
walreceiver honors wal_receiver_timeout during the wait, so it will exit
if the upstream doesn't catch up in time.
To preserve ABI compatibility on back branches, the flush position from
IDENTIFY_SYSTEM is communicated via a new global variable
(WalRcvIdentifySystemLsn) rather than changing the signature of
walrcv_identify_system().
The bug was introduced in Postgres 9.3 by commit abfd192b1b5b, which
added a flush-position check in StartReplication() that rejects requests
ahead of the upstream server's WAL flush position.
Author: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Backpatch-through: 14
Discussion: https://postgr.es/m/CA+nrD2cTuTkkX5WXVZengTYYZbAO6zV8K+Tri-R0fbLFuoyMBA@mail.gmail.com M src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
M src/backend/replication/walreceiver.c
M src/backend/utils/activity/wait_event_names.txt
M src/include/replication/walreceiver.h
M src/test/recovery/meson.build
A src/test/recovery/t/055_cascade_reconnect.pl
Fix planner's nullability/strictness logic for ScalarArrayOpExpr.
commit : 26d6b7dc9ec815f54472c7b08b0b83098007e361
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Tue, 28 Jul 2026 16:08:46 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Tue, 28 Jul 2026 16:08:46 -0400 find_nonnullable_rels and find_nonnullable_vars mistakenly treated a
ScalarArrayOpExpr that could return FALSE as strict, but that's okay
only at top level of a qual expression; further down, we've got to
insist on a guaranteed-NULL result. The result was that we could draw
mistaken conclusions about whether outer joins can be simplified, if
the decision hinged on a non-top-level ScalarArrayOpExpr with a
potentially-empty array argument.
I believe this error dates to commit 72a070a36, which taught
find_nonnullable_rels to descend into non-top-level parts of qual
expressions. is_strict_saop (added earlier by 72153c058) already had
enough intelligence to do the case correctly, but it wasn't passed the
proper flag, ie "top_level" needs to be passed for "falseOK".
e006a24ad copied that mistake into find_nonnullable_vars.
Later, over-eager refactoring in commit 2f153ddfd broke
contain_nonstrict_functions' handling of ScalarArrayOpExpr by treating
it as though it were no different from an OpExpr. It is, because
we must also prove the array is non-empty before concluding that the
expression is strict. This could result in misclassifying an
expression as strict when it is not, leading to assorted planning
mistakes such as inlining a SQL function that shouldn't be inlined.
We can almost fix this by just re-adding the previous handling of
ScalarArrayOpExpr in that function, but doing only that would lead to
also calling check_functions_in_node() and thus redundantly checking
the operator's strictness. Avoid that by turning the if-series into
an else-if chain, as it arguably should have been all along.
The reason these errors have escaped detection for decades is that
they are exposed only in arcane corner cases. ScalarArrayOpExpr with
an empty array isn't typical usage, and even when that's possible
several other conditions apply before the planner can reach a mistaken
conclusion. While it's possible to build test cases demonstrating
these mistakes, I (tgl) judged them too indirect and special-purpose
to justify consuming regression test cycles forevermore.
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAJTYsWV3vqRJmST-gv1NsXEef-zOnjVJpYS910aBaiuMij4nFg@mail.gmail.com
Discussion: https://postgr.es/m/CAJTYsWWcLGmz0f8_QPP_Liq-fc7-geiFSCdqoq3XGeRHPPsWeA@mail.gmail.com
Backpatch-through: 14 M src/backend/optimizer/util/clauses.c
Fix logical decoding of empty prepared transactions.
commit : 8c4519c71aec0f2b78d30b6586750ce1ae7eac84
author : Masahiko Sawada <msawada@postgresql.org>
date : Tue, 28 Jul 2026 12:33:40 -0700
committer: Masahiko Sawada <msawada@postgresql.org>
date : Tue, 28 Jul 2026 12:33:40 -0700 A two-phase transaction that is assigned an XID but produces no change
to be decoded -- for example, one that only acquires row locks via
SELECT ... FOR SHARE -- has no base snapshot in the reorder
buffer. ReorderBufferReplay() already skips such a transaction at
PREPARE time and never invokes the begin_prepare/change/prepare
callbacks for it, but ReorderBufferFinishPrepared() still called the
commit_prepared (or rollback_prepared) callback. As a result a
spurious COMMIT/ROLLBACK PREPARED was sent to the output plugin with
no preceding PREPARE. For the built-in subscriber this breaks
replication (the apply worker fails to find the prepared transaction),
and test_decoding could even crash.
Fix this by detecting an empty transaction (base_snapshot == NULL) in
ReorderBufferFinishPrepared() and cleaning it up without invoking the
commit/rollback prepared callbacks, mirroring the existing empty
transaction handling in ReorderBufferReplay().
On v18 and newer versions, commit 072ee847ad4 changed
ReorderBufferPrepare() to send the prepare whenever it had not already
been sent, which also fires for empty transactions and emits a
spurious PREPARE. On those branches ReorderBufferPrepare() is
therefore additionally guarded with base_snapshot != NULL. This guard
and the Assert(!rbtxn_sent_prepare()) added in
ReorderBufferFinishPrepared(), are not necessary on v17 and older
versions: there ReorderBufferPrepare() only sends a prepare for
concurrently-aborted transactions (which never applies to an empty
transaction) and the RBTXN_SENT_PREPARE flag does not exist.
Back-patch to v14, where decoding of two-phase transactions was
introduced.
Bug: #19556
Reported-by: Alexander Kozhemyakin <a.kozhemyakin@postgrespro.ru>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/19556-daa6d7ea65054d48@postgresql.org
Backpatch-through: 14 M contrib/test_decoding/expected/twophase.out
M contrib/test_decoding/sql/twophase.sql
M src/backend/replication/logical/reorderbuffer.c
M src/test/subscription/t/021_twophase.pl
Fix pg_get_publication_tables() failure with concurrent DROP TABLE.
commit : dcbc96685dc5483c9e723e7380e02edb3c9ec7a3
author : Masahiko Sawada <msawada@postgresql.org>
date : Tue, 28 Jul 2026 10:39:47 -0700
committer: Masahiko Sawada <msawada@postgresql.org>
date : Tue, 28 Jul 2026 10:39:47 -0700 pg_get_publication_tables() collects the OIDs of the published tables
on its first call, without locking them, and then reopens each table
later, once per result row, to compute its column list and fetch its
row filter. The reopen used table_open(), which errors out with "could
not open relation with OID" if the table has been dropped in the
meantime. This could happen for any published table without an
explicit column list, which is every table in FOR ALL TABLES and FOR
TABLES IN SCHEMA publications, but also FOR TABLE entries without a
column list. The failure is common in environments where many tables
are created and dropped while publication tables are being queried,
e.g. by table synchronization on a subscriber.
Fix by opening every table with try_table_open(), which returns NULL
if the relation no longer exists, and skipping the table in that
case. Concurrently dropped tables are thus simply absent from the
result set, which is the expected point-in-time behavior.
As a side effect, tables with an explicit column list, which were
previously returned without being opened, are now also locked with
AccessShareLock, so the function can block behind concurrent DDL on
such tables where it previously did not.
Backpatch to v16, where we added the table_open() call in
pg_get_publication_tables().
Author: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Ajin Cherian <itsajin@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://www.postgresql.org/message-id/CALj2ACVYYooWH-5tJ6cPKkU%2BmutVxwb_z4S%2BqAi-zdrFqxXE2Q%40mail.gmail.com
Backpatch-through: 16 M src/backend/catalog/pg_publication.c
A src/test/isolation/expected/pub-concurrent-drop.out
M src/test/isolation/isolation_schedule
A src/test/isolation/specs/pub-concurrent-drop.spec
M src/tools/pgindent/typedefs.list
Restore vacuum_delay_point() in GIN posting-tree leaf vacuum
commit : ba5e4632959027d34ec0254e1597315c3fea4c1e
author : Alexander Korotkov <akorotkov@postgresql.org>
date : Tue, 28 Jul 2026 10:50:13 +0200
committer: Alexander Korotkov <akorotkov@postgresql.org>
date : Tue, 28 Jul 2026 10:50:13 +0200 Commit fd83c83d094 turned the recursive posting-tree cleanup in
ginVacuumPostingTreeLeaves() into an iterative sweep that follows the
tree's leaf pages via their rightlinks. The recursive version called
vacuum_delay_point() while processing the tree, but that call was removed
and never re-added to the new loop. As that commit only set out to fix a
deadlock, the removal appears to have been unintentional.
Consequently the leaf-page sweep of a single posting tree runs with no
vacuum_delay_point(), and therefore no CHECK_FOR_INTERRUPTS(). A posting
tree stores all the TIDs for one indexed key, so for a frequently
occurring key it can span a large number of leaf pages. While such a
tree is being vacuumed the operation ignores vacuum_cost_delay and does
not respond to query cancellation or statement_timeout; an autovacuum
worker likewise cannot be interrupted mid-sweep when another backend
requests a conflicting lock.
Restore the call, placed after the current page has been unlocked and
released so that no buffer content lock is held across a potential delay
(cf. 21c27af65fb). The sibling loops in ginbulkdelete() and
ginvacuumcleanup() already call vacuum_delay_point() once per page.
Author: Paul Kim <mok03127@gmail.com>
Co-authored-by: Alexander Korotkov <aekorotkov@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Reviewed-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/178447127453.110.12276981925360691905%40mail.gmail.com
Backpatch-through: 14 M src/backend/access/gin/ginvacuum.c
Fix propagation of indimmediate flag in index_create_copy()
commit : 28269fed661afce4ba9a9fd0bf6ce8c2f778f12f
author : Michael Paquier <michael@paquier.xyz>
date : Tue, 28 Jul 2026 08:35:14 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Tue, 28 Jul 2026 08:35:14 +0900 index_create_copy is used to create copy definitions of existing indexes.
Currently, it passes 0 as constr_flags to index_create(), which results
in the copied index to always be created as immediate (indimmediate set
to true). For deferrable unique constraints, it means that the
transient index used during the phase 2 of REINDEX CONCURRENTLY forces
immediate constraint checks on concurrent inserts, which can cause
unexpected constraint violations based on the definition of the parent
table, inconsistently set in the copied index.
To fix this without violating the contract of constr_flags (which should
only be used when creating constraints) and without relaxing the strict
assertion in index_create(), this introduces a new index creation flag:
INDEX_CREATE_DEFERRABLE. If set, a copied index's indimmediate is set
to false, meaning that unique constraints are not enforced immediately
on insertion, but at transaction commit time.
An isolation test for REINDEX CONCURRENTLY is added, based on an
injection point waiting after phase 1 of the operation, where an index
copy has been built and is able to accept DMLs for its validation in
phase 2. The test is tentatively backpatched down to v17.
INJECTION_POINT() is outside a transaction context, which should be fine
on HEAD since 8daeaa9b642c but I suspect may cause issues in v19 and
older branches due to the wait facility depending on condition variables
and a DSM setup, but let's see what the buildfarm tells.
Author: Nitin Motiani <nitinmotiani@google.com>
Discussion: https://postgr.es/m/CAH5HC97JmjPpgiQOqW9xm8qXhNiu7zZ1Qh+FfhEESJuDv69kuQ@mail.gmail.com
Backpatch-through: 14 M src/backend/catalog/index.c
M src/backend/commands/indexcmds.c
M src/include/catalog/index.h
M src/test/modules/injection_points/Makefile
A src/test/modules/injection_points/expected/reindex_concurrently_deferred.out
M src/test/modules/injection_points/meson.build
A src/test/modules/injection_points/specs/reindex_concurrently_deferred.spec
Fix another empty nbtree index SSI race.
commit : 8434c938598d64f972aceb564104397787a21997
author : Peter Geoghegan <pg@bowt.ie>
date : Sat, 25 Jul 2026 12:01:30 -0400
committer: Peter Geoghegan <pg@bowt.ie>
date : Sat, 25 Jul 2026 12:01:30 -0400 Commit f9b7fc65 fixed a race when predicate-locking completely empty
btrees: without a buffer lock held, a matching key could be inserted
between _bt_search and the PredicateLockRelation call, so the scan would
miss concurrently inserted tuples while the writer wouldn't see the
reader's predicate lock. That commit only fixed _bt_first's _bt_search
path, though. Scans without useful insertion scan keys return early
from _bt_first via _bt_endpoint, which still didn't recheck if the
relation was empty.
To fix, add handling to _bt_endpoint that is analogous to the handling
added to _bt_search by commit f9b7fc65.
Author: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-WzkNoTn3yXY0iGkSuavJ+sL8EROf+kitW+_2v2tJVWuKmA@mail.gmail.com
Backpatch-through: 14 M src/backend/access/nbtree/nbtsearch.c
psql: Allow pg_read_all_stats to see database size in \l+
commit : 41949c6f32789301d37f065c403ce694ec3ba959
author : Fujii Masao <fujii@postgresql.org>
date : Sat, 25 Jul 2026 19:09:19 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Sat, 25 Jul 2026 19:09:19 +0900 pg_database_size() allows access to users who have either CONNECT
privilege on the target database or privileges of the pg_read_all_stats
role. However, previously, psql's \l+ checked only for CONNECT,
so users with privileges of pg_read_all_stats still saw "No Access" for
databases they could not connect to.
Fix this by making \l+ also check
pg_has_role('pg_read_all_stats', 'USAGE'), matching
pg_database_size()'s permission rules.
For back branches, emit the pg_read_all_stats check only when
connected to PostgreSQL 10 or later, since earlier releases do not have
that predefined role.
Backpatch to all supported versions.
Author: Christoph Berg <myon@debian.org>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/amCo6qRmnfPVk4-V@msg.df7cb.de
Backpatch-through: 14 M doc/src/sgml/ref/psql-ref.sgml
M src/bin/psql/describe.c
injection_points: Clear waiter slot on error and exit
commit : 821a4b4d074cb89d3f85f57d22896a63e9405b6a
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 23 Jul 2026 14:37:48 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 23 Jul 2026 14:37:48 +0900 injection_wait() only clears its slot in the waiter array after the
wait loop finishes. When the waiting query is canceled or the backend
is terminated (wait look has a CHECK_FOR_INTERRUPS), the slot leaks.
Later wakeups of the same point then bump the counter of the leaked slot
instead of the real waiter, that sleeps forever. Repeated leaks can
exhaust all the slots.
The code is changed so as the waiting loop is wrapped with
PG_ENSURE_ERROR_CLEANUP, so as the injection point slots, that are
shared resources, can be cleaned up on ERROR as much as a FATAL.
An isolation test is added: cancel one waiter, terminate another waiter,
then check that a later waiter still receives a wakeup. Without the
fixed code, the test would fail on timeout.
Author: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAN4CZFO+KF=cc0-iEg28RhqRBp_fTs6D4b8b7D7DB-pGYP3Ccg@mail.gmail.com
Backpatch-through: 17 M src/test/modules/injection_points/Makefile
A src/test/modules/injection_points/expected/wait_cleanup.out
M src/test/modules/injection_points/injection_points.c
M src/test/modules/injection_points/meson.build
A src/test/modules/injection_points/specs/wait_cleanup.spec
walsummarizer: Guard against WAL files whose tail ends are not valid.
commit : d28cdf46e6a4d55cd324b8db6148f6ebc552f52e
author : Robert Haas <rhaas@postgresql.org>
date : Wed, 22 Jul 2026 08:47:44 -0400
committer: Robert Haas <rhaas@postgresql.org>
date : Wed, 22 Jul 2026 08:47:44 -0400 SummarizeWAL documents that maximum_lsn should be passed as "the switch
point when reading a historic timeline, or the most-recently-measured end of
WAL when reading the current timeline." But the caller always passed the
most recently measured end-of-WAL even when reading from a historic
timeline, due to an oversight on my part. Fix that.
As far as I can determine, for this to become an issue in practice, it's
necessary to have a corrupted WAL file in the archive. SummarizeWAL checks
that every record it processes both starts and ends before switch_lsn; so if
all the WAL files in the archive are valid, SummarizeWAL will still discover
where it should stop summarizing and do the right thing. However, if
there's a corrupted file in the WAL archive, and if it is also the case that
the end of the current timeline has advanced past the switch point, then the
incorrect maximum_lsn value can result in trying to read an invalid record
and erroring out, which leads repeatedly retrying and failing with an error
every time.
One way this could occur is if a new primary is promoted and creates a
.partial file, and the user manually renames that file to remove the suffix,
and it is then archived. In that situation, the tail end of the file need
not be valid WAL, and that could lead to a stuck WAL summarizer.
Reported-by: Fabrice Chapuis <fabrice636861@gmail.com>
Analyzed-by: Thom Brown <thom@linux.com> (using claude)
Discussion: http://postgr.es/m/CAA5-nLDdvGMkN6Z-GaHGHG5T7QWEgv4YoHO7XvOJbeD00cghNg@mail.gmail.com
Backpatch-through: 17 M src/backend/postmaster/walsummarizer.c
doc: Granting TRIGGER or REFERENCES on table is dangerous.
commit : 2b1054be851f6f601c4527d3814427b9aa4feb4e
author : Robert Haas <rhaas@postgresql.org>
date : Mon, 20 Jul 2026 13:36:39 -0400
committer: Robert Haas <rhaas@postgresql.org>
date : Mon, 20 Jul 2026 13:36:39 -0400 It's always been the case that granting these privileges to users that
you don't fully trust was a bad idea, but it hasn't always been
obvious to people reading the documentation that this is the case.
To prevent confusion, and also repeated reports to pgsql-security,
mention it explicitly.
Discussion: http://postgr.es/m/CA+TgmobrjCHBuWHrvX3=2vndUCO2thUOdevrCcMDFW86cqCYvw@mail.gmail.com
Reviewed-by: Nathan Bossart <nathandbossart@gmail.com>
Backpatch-through: 14 M doc/src/sgml/ddl.sgml
Fix restore of partitions with exclusion constraints
commit : 1d6c654c8189cf198bc4059a9a0c9a51502e4b5f
author : Álvaro Herrera <alvherre@kurilemu.de>
date : Mon, 20 Jul 2026 17:21:20 +0200
committer: Álvaro Herrera <alvherre@kurilemu.de>
date : Mon, 20 Jul 2026 17:21:20 +0200 Commit 8c852ba9a4 allowed exclusion constraints to be added to
partitioned tables, but wasn't careful to verify that pg_restore worked
correctly for them. Fix that by making CompareIndexInfo() more
selective about what needs to be rejected.
Author: Japin Li <japinli@hotmail.com>
Reported-by: Keith Paskett <keith.paskett@logansw.com>
Discussion: https://postgr.es/m/2A40921D-83AB-411E-ADA6-7E509A46F1E4@logansw.com M src/backend/catalog/index.c
M src/test/regress/expected/indexing.out
M src/test/regress/sql/indexing.sql
Skip unnecessary get_relids_in_jointree() when there are no PHVs
commit : b308eb3661bf41fa97e27909bf008871f438894c
author : Richard Guo <rguo@postgresql.org>
date : Mon, 20 Jul 2026 12:13:11 +0900
committer: Richard Guo <rguo@postgresql.org>
date : Mon, 20 Jul 2026 12:13:11 +0900 Commit 1df9e8d96 made remove_useless_result_rtes() compute the set of
baserels in the jointree, to pass down to the find_dependent_phvs()
checks. But those checks are no-ops when the query contains no PHVs,
since find_dependent_phvs() and find_dependent_phvs_in_jointree() both
return early in that case. So we can avoid the
get_relids_in_jointree() scan altogether when root->glob->lastPHId is
zero, leaving baserels as NULL.
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAMbWs49H275KzgZr3Cd1Hy+6Lmwp35bZ+5PrVc62k3HDLj6hNQ@mail.gmail.com
Backpatch-through: 16 M src/backend/optimizer/prep/prepjointree.c
Fix edge case in remove_useless_result_rtes() with outer joins.
commit : cdcec567da1ba72e1cf9daa8356463ca23682f54
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Sat, 18 Jul 2026 14:09:10 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Sat, 18 Jul 2026 14:09:10 -0400 find_dependent_phvs() and find_dependent_phvs_in_jointree() decide
whether a PlaceHolderVar depends on the RTE_RESULT rel we're
considering removing by comparing the PHV's phrels to a singleton set
containing that rel's RT index, reasoning that if phrels contains any
other relid bits then those define an appropriate place where we can
evaluate the PHV. But since this code was originally written, we've
redefined phrels to include outer-join relids, and that breaks this
logic, potentially allowing us to remove an RTE_RESULT that leaves no
valid place to evaluate the PHV. The planner doesn't throw an error
when that happens, but it does produce an incorrect plan that will not
replace the PHV's value with NULL when needed.
In the known test case for this bug, the "extra" OJ relid is one that
we've actually decided to remove but haven't yet cleaned out of the
query's PHVs. It's not entirely clear though that that would always
be the case. Let's restore this code to the way it was designed to
work, by considering only base relids within the PHV's phrels.
Bug: #19553
Reported-by: Viktor Leis <leis@in.tum.de>
Author: Matheus Alcantara <matheusssilv97@gmail.com>
Co-authored-by: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19553-4561747f93f368a7@postgresql.org
Backpatch-through: 16 M src/backend/optimizer/prep/prepjointree.c
M src/test/regress/expected/join.out
M src/test/regress/sql/join.sql
Fix GiST index-only scan column alignment issue.
commit : 355faed5a24998859a8477cc17e6cd62a0de2214
author : Peter Geoghegan <pg@bowt.ie>
date : Fri, 17 Jul 2026 15:53:02 -0400
committer: Peter Geoghegan <pg@bowt.ie>
date : Fri, 17 Jul 2026 15:53:02 -0400 An index-only scan filled its result slot from the HeapTuple an index AM
returns in scan->xs_hitup by deforming it with the virtual slot's own
tuple descriptor (during GiST and SP-GiST index-only scans). But index
AMs form that heap tuple using their own descriptor, scan->xs_hitupdesc.
The AM's descriptor may disagree with the IoS virtual slot's descriptor
about each column's precise alignment, leading to "can't happen" errors
in certain rare edge cases. Hard crashes were possible but much less
likely.
To fix, deform the tuple with the descriptor it was formed with. This
is simpler, and makes xs_hitup handling (used by GiST and SP-GiST)
uniform with the nearby existing xs_itup handling (used by nbtree).
In practice this issue was very unlikely to be hit (it was found during
testing of a patch that will change the table AM API used during index
scans). The only currently affected core opclass is GiST's range_ops.
It was only possible for the datum to be accessed at an incorrectly
aligned offset when reading the second or subsequent column from a
multicolumn GiST index. This couldn't happen in the common case where
the datum used an unaligned short varlena header. Moreover, an earlier
column had to leave the range datum at an offset where the two
alignments actually disagree (e.g., an odd-length varlena datum).
Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Tomas Vondra <tomas@vondra.me>
Discussion: https://postgr.es/m/CAH2-WzkGXa2SKnebdW29RT1hCcQBo_p03v3iqif2u9bjzLB-aQ@mail.gmail.com
Backpatch-through: 14 M src/backend/executor/nodeIndexonlyscan.c
M src/test/regress/expected/gist.out
M src/test/regress/sql/gist.sql
meson: Fix ccache issues when using precompiled headers with gcc
commit : fc358af65e2a366012804eecb24a319335b80229
author : Andres Freund <andres@anarazel.de>
date : Fri, 17 Jul 2026 11:23:18 -0400
committer: Andres Freund <andres@anarazel.de>
date : Fri, 17 Jul 2026 11:23:18 -0400 Unfortunately the combination of gcc, precompiled headers, ccache and meson
currently is not safe without further options. The dependencies emitted by gcc
are insufficient to trigger rebuilds when headers "below" the precompiled
headers are changed. Whether that's a ccache, gcc or meson bug is
debatable. Luckily gcc's -fpch-deps option fixes the issue.
This problem occasionally leads to build failures, e.g. if only c.h,
postgres.h or pg_config_manual.h change. That's e.g. the case when creating a
new major version branch.
Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Reviewed-by: Jelte Fennema-Nio <postgres@jeltef.nl>
Discussion: https://postgr.es/m/CAN55FZ0tqR6Xz%3DiVFLc1BBoLOEHU775ARhcGYwggHA3XLA%3DoQg%40mail.gmail.com
Discussion: https://postgr.es/m/CA+hUKG+s7Yvt0PUnSQUEjCjysV-7-51n9B1h468Le3VJi0x4ZQ@mail.gmail.com
Discussion: https://postgr.es/m/phsrssp75npoyalqsolcd7fmnmlbzbmquc2p7w7mqjlw7432jk@bzskz3luyjvb
Discussion: https://github.com/ccache/ccache/issues/1686
Backpatch-through: 16, where meson support was added M meson.build
Doc: Clarify DROP SUBSCRIPTION behavior after SET (slot_name = NONE).
commit : ee1cffbb80a302f4d2336b601466a21d53ce55c0
author : Amit Kapila <akapila@postgresql.org>
date : Fri, 17 Jul 2026 09:26:12 +0530
committer: Amit Kapila <akapila@postgresql.org>
date : Fri, 17 Jul 2026 09:26:12 +0530 The previous text claimed that once the slot is disassociated with
ALTER SUBSCRIPTION ... SET (slot_name = NONE), DROP SUBSCRIPTION "will no
longer attempt any actions on a remote host". That is inaccurate:
DROP SUBSCRIPTION may still connect to the publisher to drop
internally-created table synchronization slots when some table
synchronization is left unfinished. Reword to describe this, and note
that if the publisher is unreachable those slots (and the main slot, if
it still exists) must be dropped manually to avoid indefinitely reserving
WAL.
Reported-by: Jeff Davis <pgsql@j-davis.com>
Author: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 14
Discussion: https://postgr.es/m/CAA4eK1+tyYSpPxMBy1974kjivuGeR7YY=yopwRGrK3+vCTysdg@mail.gmail.com
Discussion: https://postgr.es/m/D908370F-2695-4231-851D-17179A6A6F2A@gmail.com M doc/src/sgml/ref/drop_subscription.sgml
Fix wrong variable offset sanity check.
commit : 0cb713b120bab0255ac039972f4141d2993eeb79
author : Peter Geoghegan <pg@bowt.ie>
date : Thu, 16 Jul 2026 18:55:30 -0400
committer: Peter Geoghegan <pg@bowt.ie>
date : Thu, 16 Jul 2026 18:55:30 -0400 Commit c7aeb775 rewrote the HOT-chain offset sanity checks in three
places, but in heap_get_root_tuples it accidentally tested offnum -- the
outer loop variable, which is already bounded by the loop condition --
instead of nextoffnum, the offset actually passed to PageGetItemId. The
pre-c7aeb775 check tested nextoffnum.
With the check ineffective, a stale t_ctid could make PageGetItemId read
past the end of the line pointer array (which is data corruption that we
expect to be able to catch here).
Author: Peter Geoghegan <pg@bowt.ie>
Reported-by: Konstantin Knizhnik <knizhnik@garret.ru>
Discussion: https://postgr.es/m/87c7d8a4-3a82-4334-bee6-e8c2ad3f3293@garret.ru
Backpatch-through: 15 M src/backend/access/heap/pruneheap.c
Check CREATE_REPLICATION_SLOT response shape in libpqwalreceiver
commit : 1423a6efd018b27352c24198270770bc5ca6cb97
author : Fujii Masao <fujii@postgresql.org>
date : Thu, 16 Jul 2026 13:38:34 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Thu, 16 Jul 2026 13:38:34 +0900 Previously, libpqrcv_create_slot() checked only that
CREATE_REPLICATION_SLOT returned PGRES_TUPLES_OK before reading
values from the first row. If the server unexpectedly returned an
invalid result, such as zero rows, PQgetvalue() could return NULL,
leading to a crash while parsing the LSN.
Other replication commands, such as IDENTIFY_SYSTEM, already validate
the response shape before accessing result values, but
CREATE_REPLICATION_SLOT did not.
Fix this by verifying that CREATE_REPLICATION_SLOT response contains
exactly one row with four fields, and report a protocol violation otherwise.
Backpatch to all supported versions.
Bug: #19547
Reported-by: Yuelin Wang <1217816127@qq.com>
Author: Kenny Chen <kennychen851228@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/19547-f7986f668f71e788@postgresql.org
Discussion: https://postgr.es/m/CAPXstDtW2iqe+DJAOTQTX+rRziJp2UhZSo1+HRj1COAtbu+nKw@mail.gmail.com
Backpatch-through: 14 M src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
doc: Fix log_parameter_max_length docs to reference log_min_duration_statement
commit : 39a9c4079ccae336b012cc97df00381aef1c5be0
author : Fujii Masao <fujii@postgresql.org>
date : Thu, 16 Jul 2026 13:35:36 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Thu, 16 Jul 2026 13:35:36 +0900 The documentation for log_parameter_max_length said it affects messages
generated by log_duration. However, log_duration alone does not log bind
parameter values, so this is misleading.
This commit updates the documentation to reference log_min_duration_statement,
which can log bind parameters, to better reflect actual behavior.
Backpatch to all supported versions.
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Surya Poondla <suryapoondla4@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwGnCVMVz8-LU9F8Sh57bkQX3jMZzx7age7M0LFEz5=Fog@mail.gmail.com
Backpatch-through: 14 M doc/src/sgml/config.sgml
Test that VM clear registers VM buffers
commit : 0672134309afb0f378cf31bf4eedb8e2aab57456
author : Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 17:43:38 -0400
committer: Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 17:43:38 -0400 The WAL summarizer only tracks registered buffers, so unregistered VM
clears are ommitted from incremental backups, corrupting the restored
visibility map. Test those cases are now fixed.
Author: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/oqcsevg35xjan2327x5kdfth6q4fgeqboxfo3v3imeyih2uiny%406sez5dzxl6nt
Backpatch-through: 17 M src/bin/pg_combinebackup/Makefile
M src/bin/pg_combinebackup/meson.build
A src/bin/pg_combinebackup/t/012_vm_consistency.pl
Fix VM clear WAL logging by registering VM blocks
commit : c0d9864f5ce47902dd258bb61dd89ada6d020b55
author : Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 17:43:38 -0400
committer: Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 17:43:38 -0400 Heap WAL records that clear bits on the visibility map (like inserts and
deletes) did not register the visibility map blocks they modified.
Because the WAL summarizer only records registered blocks, an
incremental backup taken over such operations would omit the changed VM
pages. On restore, the VM would retain stale all-visible/all-frozen
bits, which can cause wrong results from index-only scans and incorrect
relfrozenxid advancement due to vacuum page skipping.
Not registering the VM buffer also meant we never emitted FPIs of VM
pages when clearing bits. A torn VM page won't raise an error because
the VM is read with ZERO_ON_ERROR; with checksums on, it would be
detected and zeroed, but with checksums off, it is accepted as-is and
can lead to data corruption.
Fix this by registering the VM buffer in the WAL record when clearing VM
bits. The VM buffer must now be locked throughout the critical section
that modifies the VM and heap pages and emits the WAL record. This can
slow down operations that clear the VM, since the VM lock is held longer
and VM FPIs may be emitted, but it is required for correctness.
Note that this fix does not repair existing incremental backups.
Author: Melanie Plageman <melanieplageman@gmail.com>
Author: Andres Freund <andres@anarazel.de>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/flat/CAAKRu_bn%2Be7F4yPFBgFbnP%2BsyJRKyNK092bjD2LKvZW7O4Svag>
Backpatch-through: 17 M contrib/pg_surgery/heap_surgery.c
M src/backend/access/heap/heapam.c
M src/backend/access/heap/visibilitymap.c
M src/bin/pg_walsummary/t/002_blocks.pl
M src/include/access/heapam_xlog.h
M src/include/access/visibilitymap.h
Introduce macros for WAL block reference IDs of some heap record types
commit : 7edec8b5784130b9c175cd8f5ab4d029d4502453
author : Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 17:43:38 -0400
committer: Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 17:43:38 -0400 When registering a buffer with the WAL machinery, the caller assigns it a
block reference ID, and replay must read each block back by that same ID.
Today these IDs are bare integers assigned by convention (0, 1, 2, ...),
which is easy to follow when a record registers a single block, or when the
blocks are handled during replay in their registration order.
An upcoming bug fix registers up to two visibility map blocks in addition
to the heap block(s) when clearing the VM, and these are not handled during
replay in a straightforward 1:1, in-registration-order fashion. Relying on
bare integers for the block IDs in that case is error-prone.
Introduce macros naming the block reference IDs for the heap record types
that the upcoming commit extends to register visibility map blocks, so the
registration and replay sites refer to the same block by a meaningful name.
Author: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/66mqpfyti3qhfttcsv6r2lbvqqd32rrmpn6i47ovrsnvguts46%40gou54xc>
Backpatch through: 17 M src/backend/access/heap/heapam.c
M src/include/access/heapam_xlog.h
Include last block in FSM vacuum of bulk extended relation
commit : 768ae083ebac8e886d2fa1754eb27f1deabb5704
author : Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 15:49:59 -0400
committer: Melanie Plageman <melanieplageman@gmail.com>
date : Wed, 15 Jul 2026 15:49:59 -0400 When bulk-extending a relation, we add the newly-added blocks that we
won't immediately use to the free space map and then call
FreeSpaceMapVacuumRange() to propagate that free space up the FSM tree,
so other backends can find and reuse it.
However, the end block argument to FreeSpaceMapVacuumRange() is
exclusive, and we passed the number of the last added block (since
00d1e02be24). If that block was the first one covered by a new FSM page,
its free space wasn't propagated up the tree and was therefore invisible
to FSM searches until the next FSM vacuum.
Fix by passing the block number one past the last added block, so the
full range is vacuumed.
Author: Jingtang Zhang <mrdrivingduck@gmail.com>
Reviewed-by: Melanie Plageman <melanieplageman@gmail.com>
Discussion: https://postgr.es/m/flat/CAPsk3_Bx_vdybN%3D-DZu8HLStf%2BXnuFUBkLwxouONSMkWuO9oug%40mail.gmail.com
Backpatch-through: 16 M src/backend/access/heap/hio.c
pgbench: Fix incorrect parameter name in error message
commit : 7692d8a05bfc86901aea1b16e0fa6ff86d6d2668
author : Daniel Gustafsson <dgustafsson@postgresql.org>
date : Wed, 15 Jul 2026 21:40:09 +0200
committer: Daniel Gustafsson <dgustafsson@postgresql.org>
date : Wed, 15 Jul 2026 21:40:09 +0200 Commit 6f164e6d17616 accidentally mistyped --client as --clients in
the error message. Backpatch down to v15 where the it was introduced.
Author: Semih Doğan <semih702do@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/CALOtZ7tuWisV=v0cUY_q6PLHJ-fOiQ7ZN476JwmM0PyV0t5i7Q@mail.gmail.com
Backpatch-through: 15 M src/bin/pgbench/pgbench.c
M src/bin/pgbench/t/002_pgbench_no_server.pl
Add additional sanity checks when reading a blkreftable.
commit : 0c5516a0df97e1e707ea5e9e08712e29ce4ee047
author : Robert Haas <rhaas@postgresql.org>
date : Wed, 15 Jul 2026 13:04:32 -0400
committer: Robert Haas <rhaas@postgresql.org>
date : Wed, 15 Jul 2026 13:04:32 -0400 Code elsewhere in the system assumes that fork numbers and chunk sizes
are within bounds, so the code that reads those quantities from disk
should validate that they are. Without these additional checks, a
corrupted file can cause us to index off the end of fork number or chunk
entry arrays, potentially resulting in a crash.
Reported-by: oxsignal <awo@kakao.com> (chunk sizes)
Reported-by: Robert Haas <rhaas@postgresql.org> (fork numbers)
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: http://postgr.es/m/CA+TgmoYP8RKoBGosS7C6Fdr-GNCfyz_W1zmK=Tx1Fe0ZvzGh0g@mail.gmail.com
Backpatch-through: 17 M src/common/blkreftable.c
Make max_pinned_buffers be > 0, don't just Assert that it is.
commit : 3d3b8872814362e061802703bb5d92fe050fc602
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Wed, 15 Jul 2026 13:24:00 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Wed, 15 Jul 2026 13:24:00 -0400 It was possible to trigger read_stream_begin_relation's
assertion that it calculated nonzero max_pinned_buffers,
in scenarios with unreasonably small numbers of buffers.
There seems to be no visible problem in non-Assert builds.
The bug occurs only in v17 (the first branch containing
this logic), because commit 92fc6856c replaced that Assert
with a runtime clamp. I won't risk back-patching that entire
commit, but let's copy just this minimal fix.
Bug: #19551
Reported-by: Roman Zharkov <r.zharkov@postgrespro.ru>
Author: Thomas Munro <thomas.munro@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19551-d4a55b8fe81db4f2@postgresql.org
Backpatch-through: 17 only M src/backend/storage/aio/read_stream.c
Include check on polpermissive relcache for policies
commit : 2d1ed2c1dd8e8eb4daa300f574331864a6c49688
author : Michael Paquier <michael@paquier.xyz>
date : Wed, 15 Jul 2026 10:03:41 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Wed, 15 Jul 2026 10:03:41 +0900 equalPolicy() is used in the relation cache to check if two policy
definitions are equivalent, but missed to check for polpermissive.
ALTER POLICY cannot switch a policy to be PERMISSIVE or RESTRICTIVE, so
this would need a dropped and then re-created policy, which would
trigger a relcache invalidation. Anyway, there is no harm in being
consistent in the check, and if one decides to add an ALTER POLICY to
switch PERMISSIVE or RESTRICTIVE, we would be silently in trouble.
Author: Andreas Lind <andreaslindpetersen@gmail.com>
Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at>
Discussion: https://postgr.es/m/CAMxA3rv1CS6R7JR5ojz-3CmCEnZEFrqu+XXTnGbLRWrjJRH7sA@mail.gmail.com
Backpatch-through: 14 M src/backend/utils/cache/relcache.c
Shorten pg_attribute_always_inline to pg_always_inline
commit : 885dc83380999842fb568af292529ea089c93d89
author : Tomas Vondra <tomas.vondra@postgresql.org>
date : Sat, 11 Jul 2026 15:14:50 +0200
committer: Tomas Vondra <tomas.vondra@postgresql.org>
date : Sat, 11 Jul 2026 15:14:50 +0200 The pg_attribute_always_inline macro name is so long it forces pgindent
to format the code in strange ways. Which may incentivize patch authors
to either structure the code in strange ways (e.g. reorder prototypes),
use shorter names, etc. Neither is very desirable for code readability.
This shortens the name by removing the _attribute_ part. It also makes
it more consistent with pg_noinline, which does not have the _attribute_
part either.
Backpatched to all supported branches, to prevent conflicts when
backpatching other fixes. The backbranches however keep both the old and
new macro name, so that existing code keeps working.
Author: Andres Freund <andres@anarazel.de>
Reviewed-by: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Tomas Vondra <tomas@vondra.me>
Discussion: https://postgr.es/m/bqqdehahpoa36igpictuqyn2s2mexk3t3ehidh2ffd2slb35e5@rzgksuiszgbg
Backpatch-through: 14 M src/backend/access/heap/heapam.c
M src/backend/access/transam/xlog.c
M src/backend/executor/execExprInterp.c
M src/backend/executor/execTuples.c
M src/backend/executor/nodeHashjoin.c
M src/backend/storage/buffer/bufmgr.c
M src/backend/utils/cache/catcache.c
M src/include/c.h
libpq: Make error checks in the new buffer draining code more robust
commit : bab0a2db733502da5663c5aef38976cbf8711707
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 9 Jul 2026 18:34:27 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 9 Jul 2026 18:34:27 +0300 Check explicitly for pqsecure_read() returning an error. It shouldn't
fail, and we would've caught it in the check for a short read, but
better to be explicit so that the error message is more informative.
We also shouldn't update 'inEnd' when the read fails, although that
too is just pro forma as we will bail out and close the connection on
error.
Reported-by: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://www.postgresql.org/message-id/34844e8c-267c-4daf-b1e0-f26059a4a7d3@eisentraut.org
Backpatch-through: 14 M src/interfaces/libpq/fe-misc.c
M src/interfaces/libpq/fe-secure.c
ssl: Include limits.h to get INT_MAX when using LibreSSL
commit : 0958c3ea4c677e9f5900fbdc60458f5b9bb34a06
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 9 Jul 2026 18:34:24 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 9 Jul 2026 18:34:24 +0300 When compiling against OpenSSL, the <limits.h> header is indirectly
included via openssl/ossl_typ.h from openssl/conf.h, but the LibreSSL
version of ossl_typ.h does not include <limits.h> which cause compiler
failure due to missing symbol (since ffd080d94fe). Fix by explicitly
including <limits.h>.
Author: Daniel Gustafsson <dgustafsson@postgresql.org>
Discussion: https://www.postgresql.org/message-id/6A9E7815-BD5A-4C31-A515-48159823406B@yesql.se
Backpatch-through: 14 M src/interfaces/libpq/fe-secure-openssl.c
doc: Clarify COPY FROM WHERE expression restrictions
commit : 4d0c3eba1dca2c40fbca734f069cdfc675c54a1b
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 8 Jul 2026 12:45:20 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 8 Jul 2026 12:45:20 +0900 Commit aa606b9316a disallowed generated columns in COPY FROM WHERE
expressions, and commit 21c69dc73f9 disallowed system columns.
However, the COPY reference page still mentions only the restriction
on subqueries.
Update the documentation to also list generated columns and system
columns as unsupported in COPY FROM WHERE expressions.
Backpatch the generated-column documentation change to all supported
versions. Backpatch the system-column documentation change to v19,
where that restriction was introduced.
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEgxErc54yVOAVWCsr1O=8pgw4oKRPuEQ9mfhkoYGR_XA@mail.gmail.com
Backpatch-through: 14 M doc/src/sgml/ref/copy.sgml
doc: Fix typo in rule-system view example
commit : 3017543b1ca97089b2db96275af65d351188eed6
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 8 Jul 2026 09:04:31 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 8 Jul 2026 09:04:31 +0900 Commit dcb00495236 accidentally changed the final expanded query's
condition to > 2 while rewriting the example into SQL operator notation.
The original query and the preceding rewritten forms all use >= 2,
and view expansion should preserve that qualification. This commit
changes the final condition from > 2 to >= 2.
Backpatch to all supported versions.
Reported-by: Yaroslav Saburov <y.saburov@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/178248467618.108999.9966122434342474006@wrigleys.postgresql.org
Backpatch-through: 14 M doc/src/sgml/rules.sgml
Fix EXPLAIN failure when deparsing SQL/JSON aggregates
commit : dcda1f07da48bcb591de47cd99fb45f841482fb5
author : Richard Guo <rguo@postgresql.org>
date : Wed, 8 Jul 2026 08:50:14 +0900
committer: Richard Guo <rguo@postgresql.org>
date : Wed, 8 Jul 2026 08:50:14 +0900 If an expression containing an aggregate is evaluated above the plan
node that computes the aggregate, as happens with window functions or
with expressions postponed to above the final sort, setrefs.c replaces
the Aggref or WindowFunc with a Var referencing the lower node's
output. For SQL/JSON aggregates such as JSON_ARRAYAGG and
JSON_OBJECTAGG, deparsing the containing JsonConstructorExpr then
failed with "invalid JsonConstructorExpr underlying node type", since
get_json_agg_constructor() did not expect a Var there.
Fix by resolving the Var back to the underlying Aggref or WindowFunc
and deparsing the constructor as if the aggregate were computed at the
current node. The JsonConstructorExpr retains the RETURNING clause
and the ABSENT/NULL ON NULL and WITH UNIQUE options, and the arguments
come from the resolved aggregate, so the original JSON aggregate
syntax is reproduced in full. This mirrors how get_agg_expr() already
looks through such a Var when deparsing a combining aggregate.
Reported-by: Thom Brown <thom@linux.com>
Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAA-aLv5QYTaMOk=Qhv6cgwceeHETZV8YJvWZ_rH+yVZCuchATA@mail.gmail.com
Backpatch-through: 16 M src/backend/utils/adt/ruleutils.c
M src/test/regress/expected/sqljson.out
M src/test/regress/sql/sqljson.sql
unicode_case.c: defend against truncated UTF8.
commit : 5e78ebca57b3630c1230d348263fddfeaaf7678e
author : Jeff Davis <jdavis@postgresql.org>
date : Tue, 7 Jul 2026 13:35:23 -0700
committer: Jeff Davis <jdavis@postgresql.org>
date : Tue, 7 Jul 2026 13:35:23 -0700 Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/c355354e6c3f4a7aafb047361b73db247260fca0.camel@j-davis.com
Backpatch-through: 17 M src/backend/utils/adt/formatting.c
M src/common/unicode/case_test.c
M src/common/unicode_case.c
libpq: Drain all pending bytes from SSL/GSS during pqReadData()
commit : 177a2a2e396c2699f6043b3aa60d28abb8805f17
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 7 Jul 2026 18:45:37 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 7 Jul 2026 18:45:37 +0300 The previous commit strengthened a workaround for a hang when large
messages are split across TLS records/GSS tokens. Because that
workaround is implemented in libpq internals, it can only help us when
libpq itself is polling on the socket. In nonblocking situations,
where the client above libpq is expected to poll, the same bugs can
show up.
As a contrived example, consider a large protocol-2.0 error coming
back from a server during PQconnectPoll(), split in an odd way across
two records:
-- TLS record (8192-byte payload) --
EEEE[...repeated a total of 8192 times]
-- TLS record (8193-byte payload) --
EEEE[...repeated a total of 8192 times]\0
The first record will fill the first half of the libpq receive buffer,
which is 16k long by default. The second record completely fills the
last half with its first 8192 bytes, leaving the terminating NULL in
the OpenSSL buffer. Since we still haven't seen the terminator at our
level, PQconnectPoll() will return PGRES_POLLING_READING, expecting to
come back when the server has sent "the rest" of the data. But there
is nothing left to read from the socket; OpenSSL had to pull all of
the data in the 8193-byte record off of the wire to decrypt it.
A real server would probably not split up the records this way, nor
keep the connection open after sending a fatal connection error. But
servers that regularly use larger TLS records can get the libpq
receive buffer into the same state if DataRows are big enough, as
reported on the list. While the PostgreSQL server doesn't use larger
TLS records like that, other non-PostgreSQL servers that implement the
wire protocol are known to do that, as well as proxies that sit
between the server and the client
This is a layering violation. libpq makes decisions based on data in
the application buffer, above the transport buffer (whether SSL or
GSS), but clients are polling the socket below the transport buffer.
One way to fix this in a backportable way, without changing APIs too
much, is to ensure data never stays in the transport buffer. Then
pqReadData's postconditions will look similar for both raw sockets and
SSL/GSS: any available data is either in the application buffer, or
still on the socket.
Building on the prior commit, make pqReadData() to drain all pending
data from the transport layer into conn->inBuffer, expanding the
buffer as necessary. This is not particularly efficient from an
architectural perspective (the pqsecure_read() implementations take
care to fit their packets into the current buffer, and that effort is
now completely discarded), but it's hopefully easier to reason about
than a full rewrite would be for the back branches.
Author: Jacob Champion <jacob.champion@enterprisedb.com>
Reviewed-by: Mark Dilger <mark.dilger@enterprisedb.com>
Reviewed-by: solai v <solai.cdac@gmail.com>
Reported-by: Lars Kanis <lars@greiz-reinsdorf.de>
Discussion: https://postgr.es/m/2039ac58-d3e0-434b-ac1a-2a987f3b4cb1%40greiz-reinsdorf.de
Backpatch-through: 14 M src/interfaces/libpq/fe-misc.c
M src/interfaces/libpq/fe-secure-openssl.c
M src/interfaces/libpq/fe-secure.c
libpq: Extend "read pending" check from SSL to GSS
commit : c162810a503f15e536710f4c5c6dd80c85d6a7f4
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 7 Jul 2026 18:45:34 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 7 Jul 2026 18:45:34 +0300 An extra check for pending bytes in the SSL layer has been part of
pqReadReady() for a very long time (79ff2e96d). But when GSS transport
encryption was added, it didn't receive the same treatment. (As
79ff2e96d notes, "The bug that I fixed in this patch is exceptionally
hard to reproduce reliably.")
Without that check, it's possible to hit a hang in gssencmode, if the
server splits a large libpq message such that the final message in a
streamed response is part of the same wrapped token as the split
message:
DataRowDataRowDataRowDataRowDataRowData
-- token boundary --
RowDataRowCommandCompleteReadyForQuery
If the split message takes up enough memory to nearly fill libpq's
receive buffer, libpq may return from pqReadData() before the later
messages are pulled out of the PqGSSRecvBuffer. Without additional
socket activity from the server, pqReadReady() (via pqSocketCheck())
will never again return true, hanging the connection.
Pull the pending-bytes check into the pqsecure API layer, where both
SSL and GSS now implement it.
Note that this does not fix the root problem! Third party clients of
libpq have no way to call pqsecure_read_is_pending() in their own
polling. This just brings the GSS implementation up to par with the
existing SSL workaround; a broader fix is left to a subsequent commit.
In preparation for the broader fix, this patch already changes the
*_read_pending() functions to return the number of bytes in the buffer
rather than just a boolean. The current callers don't need that, but
the subsequent fix will.
Author: Jacob Champion <jacob.champion@enterprisedb.com>
Discussion: https://postgr.es/m/CAOYmi%2BmpymrgZ76Jre2dx_PwRniS9YZojwH0rZnTuiGHCsj0rA%40mail.gmail.com
Backpatch-through: 14 M src/interfaces/libpq/fe-misc.c
M src/interfaces/libpq/fe-secure-gssapi.c
M src/interfaces/libpq/fe-secure-openssl.c
M src/interfaces/libpq/fe-secure.c
M src/interfaces/libpq/libpq-int.h
pg_dump: check for _beginthreadex() failure in parallel dump
commit : 4eaceec97ae2add49413918dc6ed9383fc6680b1
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 7 Jul 2026 18:11:28 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 7 Jul 2026 18:11:28 +0300 ParallelBackupStart() stored _beginthreadex()'s return value as the
worker's thread handle without checking it. On failure that value is 0,
which would later reach WaitForMultipleObjects() as a null handle, caught
only by an Assert. The fork() path already calls pg_fatal() when it
fails; do the same for _beginthreadex(), as pgbench does.
Author: Bryan Green <dbryan.green@gmail.com>
Discussion: https://www.postgresql.org/message-id/8c712d76-ecf7-4749-a6d8-dddc01f298ec@gmail.com
Backpatch-through: 14 M src/bin/pg_dump/parallel.c
Fix COUNT's logic for window run condition support
commit : be63b285e5006459c1c66d986dd3da27cbcce746
author : David Rowley <drowley@postgresql.org>
date : Tue, 7 Jul 2026 23:59:33 +1200
committer: David Rowley <drowley@postgresql.org>
date : Tue, 7 Jul 2026 23:59:33 +1200 9d9c02ccd added code to allow the executor to stop early when processing
WindowAgg nodes where a monotonic window function starts producing
values that result in a pushed-down qual no longer matching, and will
never match again due to the window function's monotonic properties.
That commit requires a SupportRequestWFuncMonotonic to exist on the
window function and for it to detect when the function is monotonic. For
COUNT(ANY) and COUNT(*), the support function failed to consider some
cases where the WindowClause used EXCLUDE to exclude certain rows from
being aggregated. Some WindowClause definitions mean we aggregate rows
that come after the current row, and when processing those rows later,
if we EXCLUDE certain rows, the monotonic property can be broken.
Wrongly treating the COUNT(*) or COUNT(ANY) aggregate as monotonic could
lead to rows being filtered that should not be filtered from the result
set.
Another issue was that the support function for the COUNT aggregate
mistakenly thought that a WindowClause without an ORDER BY meant that
the results would be both monotonically increasing and decreasing, but
that's only true when in RANGE mode, where all rows are peers.
It is possible to support various cases that do have an EXCLUDE clause,
but getting the logic correct for the exact set of cases that are valid
is quite complex and would likely better be left for a future project.
Here, we mostly disable run condition pushdown when there is an EXCLUDE
clause unless the clause is for EXCLUDE CURRENT ROW, uses COUNT(*)
(rather than COUNT(ANY)), and the window aggregate has no FILTER clause.
Bug: #19533
Reported-by: Qifan Liu <imchifan@163.com>
Author: Chengpeng Yan <chengpeng_yan@outlook.com>
Author: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: John Naylor <johncnaylorls@gmail.com>
Discussion: https://postgr.es/m/19533-413a1014e5d0e766@postgresql.org
Backpatch-through: 15 M src/backend/utils/adt/int8.c
M src/test/regress/expected/window.out
M src/test/regress/sql/window.sql
Enforce RETURNING typmod on SQL/JSON DEFAULT behavior expressions
commit : 71cd10cd249baae25bb420ea4a6d5eae9fe1dd5f
author : Amit Langote <amitlan@postgresql.org>
date : Tue, 7 Jul 2026 08:13:28 +0900
committer: Amit Langote <amitlan@postgresql.org>
date : Tue, 7 Jul 2026 08:13:28 +0900 transformJsonBehavior() coerced an ON EMPTY / ON ERROR DEFAULT
expression only when its type differed from the RETURNING type's OID.
When the base type matched but the RETURNING type carried a type
modifier (e.g. numeric(4,1) or varchar(3)), the coercion that enforces
the typmod was skipped, so the DEFAULT value could violate the
declared type:
SELECT JSON_VALUE(jsonb '{}', '$.a'
RETURNING numeric(4,1) DEFAULT 99999.999 ON EMPTY);
returned 99999.999, which 99999.999::numeric(4,1) would reject; the
value could even be stored into a numeric(4,1) column, as later
coercions trust its already-correct type label.
Fix by also coercing when the RETURNING type has a typmod, except for
a NULL constant. coerce_to_target_type() is a no-op when the typmod
already matches. The matching-OID short-circuit dates to 74c96699be3.
Reported-by: Ewan Young <kdbase.hack@gmail.com>
Author: Ewan Young <kdbase.hack@gmail.com>
Discussion: https://postgr.es/m/CAON2xHPO9f4cAmyGn1mQ=VqoS7wN5rz4yOiqudxX78zninZpCw@mail.gmail.com
Backpatch-through: 17 M src/backend/parser/parse_expr.c
M src/test/regress/expected/sqljson_jsontable.out
M src/test/regress/expected/sqljson_queryfuncs.out
M src/test/regress/sql/sqljson_jsontable.sql
M src/test/regress/sql/sqljson_queryfuncs.sql
Prevent satisfies_hash_partition from crashing with VARIADIC NULL.
commit : 52af6fef43755de40472149c9d7f1adc9bf77b5e
author : Robert Haas <rhaas@postgresql.org>
date : Mon, 6 Jul 2026 12:12:41 -0400
committer: Robert Haas <rhaas@postgresql.org>
date : Mon, 6 Jul 2026 12:12:41 -0400 Commit f3b0897a1213f46b4d3a99a7f8ef3a4b32e03572 fixed some
related problems, but overlooked this one. That commit first
appeared in PostgreSQL 11, so back-patch to all supported branches.
Backpatch-through: 14
Discussion: http://postgr.es/m/CA+TgmobsvQw3F+KRYT83=N3teh8D2t-oPR=U06QDZJE3viCJRg@mail.gmail.com
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com> M src/backend/partitioning/partbounds.c
M src/test/regress/expected/hash_part.out
M src/test/regress/sql/hash_part.sql
Restore basebackup_progress_done() to preserve ABI
commit : a240e8cd23532931ca1e5216f4f42e91fac36dfe
author : Fujii Masao <fujii@postgresql.org>
date : Mon, 6 Jul 2026 09:46:15 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Mon, 6 Jul 2026 09:46:15 +0900 Commit e7564ee8cdc, which fixed base backup progress reporting on
backup failure, removed the external function basebackup_progress_done()
because it was no longer used in core. When that change was backpatched
to v15, it introduced an ABI break, which was reported by buildfarm
member crake.
This commit restores basebackup_progress_done() to preserve ABI
compatibility, even though it is no longer used in core, rather than
updating the .abi-compliance-history file. Because external backup
tools may still call this function.
Per buildfarm member crake.
Reported-by: Andrew Dunstan <andrew@dunslane.net>
Discussion: https://postgr.es/m/CAD5tBcJ+ktrEp=PT8Gq-f=8mA2cDtZMB-hDMV4mMJ+9V46qBeQ@mail.gmail.com
Backpatch-through: 15-18 M src/backend/backup/basebackup_progress.c
M src/include/backup/basebackup_sink.h
Disallow renaming a rule to "_RETURN".
commit : e99fb3262441b47d88632b2857f03083be67f3e3
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Sat, 4 Jul 2026 11:34:26 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Sat, 4 Jul 2026 11:34:26 -0400 ON SELECT rules must be named "_RETURN", while other kinds of rules
must not be; this ancient restriction is depended on by various client
code. We successfully enforced this convention in most places, but
ALTER RULE allowed renaming a non-SELECT rule to "_RETURN". Notably,
that would break dump/restore, since the eventual CREATE RULE command
would reject the name.
While at it, remove DefineQueryRewrite's hack to substitute "_RETURN"
for the convention that was used before 7.3. We dropped other
server-side code that supported restoring pre-7.3 dumps some time ago
(notably in e58a59975 and nearby commits), but this bit was missed.
Bug: #19543
Reported-by: Adam Pickering <adamkpickering@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19543-461228e77f3b32fc@postgresql.org
Backpatch-through: 14 M src/backend/rewrite/rewriteDefine.c
M src/test/regress/expected/rules.out
M src/test/regress/sql/rules.sql
Fix btree_gist's NotEqual strategy on internal index pages.
commit : 86992769e8fb75910858f64172797f4f011e4f02
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Fri, 3 Jul 2026 13:50:14 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Fri, 3 Jul 2026 13:50:14 -0400 gbt_var_consistent() handled the <> (BtreeGistNotEqual) strategy without
distinguishing leaf from internal pages, unlike every other strategy.
In particular, it tried to apply the datatype-specific f_eq method,
which is completely wrong since internal keys might not have the same
representation as leaf keys. This led to OOB reads and potentially
crashes, and most likely to wrong query results as well.
On leaf pages we can apply the inverse of what the Equal strategy does.
On internal pages, use a correct implementation of what the previous
code intended: we can descend if the query value equals both bounds,
*so long as the bounds aren't truncated*. With truncated bounds we
don't quite know the range of what's below, so we must always descend.
Adjust the code in gbt_num_consistent() to look similar, too. This
fixes a performance buglet in that there's no need to do two comparisons
on a leaf entry, but the main point is just to keep code consistency.
Reported-by: 王跃林 <violin0613@tju.edu.cn>
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/AH*AvQCYKhQGVvPWi1GiU4oY.8.1781609375063.Hmail.3020001251@tju.edu.cn
Backpatch-through: 14 M contrib/btree_gist/btree_utils_num.c
M contrib/btree_gist/btree_utils_var.c
Prevent access to other sessions' empty temp tables
commit : 4e49f68b72dea48b2f6772b66b7565b8f652291b
author : Alexander Korotkov <akorotkov@postgresql.org>
date : Fri, 3 Jul 2026 15:53:03 +0300
committer: Alexander Korotkov <akorotkov@postgresql.org>
date : Fri, 3 Jul 2026 15:53:03 +0300 Commit ce146621 ensures that ERROR is raised if a session tries to read
pages of another session's temp table. But there is a corner case where
the other session's temp table is empty -- in this case the INSERT
command bypasses our checks and executes without any errors.
Such behavior is inconsistent and erroneous: it leaves an invalid buffer
in the temp buffers pool. Since the buffer was created for another
session's temp table, we get an error "no such file or directory" when
trying to flush it.
This commit fixes it by adding a RELATION_IS_OTHER_TEMP check in the
relation-extension path.
Backpatch to 16, because it is the first release after 31966b151e6, which
introduced a separate local relation extension function
ExtendBufferedRelLocal(), which lacks of RELATION_IS_OTHER_TEMP() check.
As this fix introduces more checks to 013_temp_obj_multisession.pl, backpatch
the whole test script to 16.
Discussion: https://postgr.es/m/CAJDiXgiX2XZBHDNo%2BzBbvku%2BtchrUurvPRaN1_40mEQ1_sG90g%40mail.gmail.com
Author: Daniil Davydov <3danissimo@gmail.com>
Reviewed-by: Jim Jones <jim.jones@uni-muenster.de>
Reviewed-by: Imran Zaheer <imran.zhir@gmail.com>
Reviewed-by: ZizhuanLiu X-MAN <44973863@qq.com>
Backpatch-through: 16 M src/backend/storage/buffer/bufmgr.c
M src/include/utils/rel.h
M src/test/modules/test_misc/t/013_temp_obj_multisession.pl
psql: Fix \df tab completion for procedures
commit : 355a4fcf943785872c9e4acbee694890582f6258
author : Fujii Masao <fujii@postgresql.org>
date : Fri, 3 Jul 2026 13:46:35 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Fri, 3 Jul 2026 13:46:35 +0900 Commit fb421231daa extended \df to include procedures, but its tab
completion continued not to show procedures.
Update \df tab completion to include procedures as well.
Backpatch to all supported versions.
Author: Erik Wienhold <ewie@ewie.name>
Reviewed-by: Surya Poondla <suryapoondla4@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/10fbfdfe-80f6-4ef9-b8b3-f7be0eb53a50@ewie.name
Backpatch-through: 14 M src/bin/psql/tab-complete.c
Remove replication slot advice from MultiXact wraparound hints
commit : a287fd85d2c536f834765c398cf6dba9c4361ea6
author : Fujii Masao <fujii@postgresql.org>
date : Fri, 3 Jul 2026 11:16:34 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Fri, 3 Jul 2026 11:16:34 +0900 Previously, MultiXactId wraparound hints suggested dropping stale
replication slots. While that advice is appropriate for transaction ID
wraparound, where replication slots can hold back XID horizons,
it was misleading for MultiXactId wraparound. Following it could lead
users to drop replication slots unnecessarily without helping resolve
the MultiXactId wraparound condition.
MultiXact cleanup is not directly delayed by replication slots.
Instead, it depends on whether old MultiXactIds can still be seen
as live by running transactions.
This commit removes the replication slot advice from MultiXactId
wraparound hints, and documents that stale replication slots are
normally not relevant to resolving MultiXactId wraparound problems.
Backpatch to all supported branches.
BUG #18876
Reported-by: Haruka Takatsuka <harukat@sraoss.co.jp>
Author: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/18876-0d0b53bad5a1f4c1@postgresql.org
Backpatch-through: 14 M doc/src/sgml/maintenance.sgml
M src/backend/access/transam/multixact.c
M src/backend/commands/vacuum.c
Fix redefinition of typedef Node in numeric.h
commit : c768637d6c29ec31438d77520fa4de37c95a78cd
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 2 Jul 2026 15:06:12 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 2 Jul 2026 15:06:12 +0900 Commit 84001a04d552 has added a forward declaration of Node, something
not allowed in C99.
Per buildfarm members longfin and sifaka.
Discussion: https://postgr.es/m/akXt_WYx0dgdH6rf@paquier.xyz
Backpatch-through: 17-18 M src/include/utils/numeric.h
Fix jsonpath .decimal() to honor silent mode
commit : ab35b8d2528641efd4b23111874665c92e7f6b65
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 2 Jul 2026 12:44:36 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 2 Jul 2026 12:44:36 +0900 The jsonpath .decimal(precision[, scale]) method built its numeric
typmod by calling numerictypmodin() through DirectFunctionCall1(), which
can throw a hard error for an incorrect set of precision and/or scale
vaulues. This breaks the silent mode supported by this function, that
should not fail.
Most of the jsonpath code uses the soft error reporting to bypass
errors, which is what this fix does by avoiding a direct use of
numerictypmodin(). Its code is refactored to use a new routine called
make_numeric_typmod_safe(), able to take an error context in input.
numerictypmodin() sets no context, mapping to its previous behavior.
The jsonpath code sets or not a context depending on the use of the
silent mode. This result leads to some nice simplifications:
numerictypmodin() feeds on an array, we can now pass directly values for
the scale and precision.
Oversight in 66ea94e8e606.
Author: Ewan Young <kdbase.hack@gmail.com>
Discussion: https://postgr.es/m/CAON2xHMaigKABiyPBBq3Sjd3gp7uWMJXnnMHt=s85V1ij3KP1w@mail.gmail.com
Backpatch-through: 17 M src/backend/utils/adt/jsonpath_exec.c
M src/backend/utils/adt/numeric.c
M src/include/utils/numeric.h
M src/test/regress/expected/jsonb_jsonpath.out
M src/test/regress/sql/jsonb_jsonpath.sql
btree_gist: fix NaN handling in float4/float8 opclasses.
commit : d215d2cc2ae181dbb201c017b43a9778c4bcf7f4
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Wed, 1 Jul 2026 13:27:22 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Wed, 1 Jul 2026 13:27:22 -0400 The float4 and float8 btree_gist opclasses compared keys with raw C
operators (==, <, >). IEEE 754 makes every comparison involving NaN
false, so GiST disagreed with the regular float comparison operators
and with the btree opclass, which uses float[4|8]_cmp_internal()
(so that all NaNs are equal and NaN sorts after every non-NaN value).
In addition, the penalty and distance functions were not careful
about NaNs, and the penalty functions could also misbehave for IEEE
infinities. Wrong answers from the penalty functions would probably
do no more than make the index non-optimal, but the distance mistakes
were visible from SQL.
To fix, make the comparison functions rely on the same NaN-aware
comparison functions the core code uses, and rewrite the penalty
and distance functions to follow the rules that NaNs are equal
but maximally far away from non-NaNs. The penalty_num() code was
formerly shared between integral and float cases, but I chose to make
two copies so that the integral cases are not saddled with the extra
logic for NaNs and infinities/overflows. I also rewrote it as static
inline functions instead of an unreadable and uncommented macro.
The float penalty functions were previously unreached by the
regression tests, so add new test cases to exercise them.
There's no on-disk format change, but users who have NaN entries
in a btree_gist index would be well advised to reindex it.
Bug: #19501
Bug: #19524
Reported-by: Man Zeng <zengman@halodbtech.com>
Reported-by: Yuelin Wang <3020001251@tju.edu.cn>
Author: Bill Kim <billkimjh@gmail.com>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19501-3bff3bbc97f1e7c9@postgresql.org
Discussion: https://postgr.es/m/19524-9559d302c8455664@postgresql.org
Discussion: https://postgr.es/m/CAMQXxcgbtD2LXfX0tpgvOizxP-XxrCHV2ZDy4By_TZnJMsxXWQ@mail.gmail.com
Backpatch-through: 14 M contrib/btree_gist/btree_float4.c
M contrib/btree_gist/btree_float8.c
M contrib/btree_gist/btree_utils_num.h
M contrib/btree_gist/data/float4.data
M contrib/btree_gist/data/float8.data
M contrib/btree_gist/expected/float4.out
M contrib/btree_gist/expected/float8.out
M contrib/btree_gist/expected/numeric.out
M contrib/btree_gist/sql/float4.sql
M contrib/btree_gist/sql/float8.sql
Clear base backup progress on backup failure
commit : e2ea6bfed8803cd8d11b5cd85f9669a57d517735
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 1 Jul 2026 23:05:34 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 1 Jul 2026 23:05:34 +0900 Previously, if a base backup failed after it had started streaming
files, pg_stat_progress_basebackup could continue to show a stale
progress entry even though the backup was no longer running. This could
be observed when the client kept the replication connection open after
the error. It is normally not observable when using pg_basebackup,
because the client disconnects after the error.
The problem was that progress reporting was cleared only after
successful completion.
This commit moves the progress reporting cleanup into the progress
sink's cleanup callback so that it is cleared after both successful
and failed backups.
Backpatch to v15. v14 has the same issue, but the fix does not apply
cleanly because it lacks the base backup sink infrastructure. Since
the bug does not affect the backup itself and is normally not
observable when using pg_basebackup, skip the v14 backpatch.
Author: Chao Li <lic@highgo.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/EA1A6CD2-EFA6-462B-9A02-03003555AB4A@gmail.com
Backpatch-through: 15 M src/backend/backup/basebackup.c
M src/backend/backup/basebackup_progress.c
M src/include/backup/basebackup_sink.h
Don't cast off_t to 32-bit type for output, bug fix
commit : 4d99e6ed640e3a214875b814d489c4d8ce8f77b1
author : Peter Eisentraut <peter@eisentraut.org>
date : Wed, 1 Jul 2026 09:40:36 +0200
committer: Peter Eisentraut <peter@eisentraut.org>
date : Wed, 1 Jul 2026 09:40:36 +0200 off_t is most likely a 64-bit integer, so casting it to a 32-bit type
for output could lose data. There are more issues like this in the
tree, but this is an instance where this could actually happen in
practice, since base backups are routinely larger than 4 GB. So this
is separated out as a bug fix.
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://www.postgresql.org/message-id/flat/20ce62fa-47fc-457b-b504-12f3c1651726%40eisentraut.org M src/backend/backup/basebackup_server.c
Document wal_compression=on
commit : 92b129945065493e35a303d1579379e6b6c51d21
author : John Naylor <john.naylor@postgresql.org>
date : Wed, 1 Jul 2026 08:50:08 +0700
committer: John Naylor <john.naylor@postgresql.org>
date : Wed, 1 Jul 2026 08:50:08 +0700 Commit 4035cd5d4 added LZ4 compression for full-page writes in WAL, and
retained "on" as a backward-compatible way to specify the builtin PGLZ
method. Document this meaning of "on" and update postgresql.conf.sample
to make the equivalence clear.
Author: Christoph Berg <myon@debian.org>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/akJDHRtXwGLTppsQ@msg.df7cb.de
Backpatch-through: 15 M doc/src/sgml/config.sgml
M src/backend/utils/misc/postgresql.conf.sample
Fix unlogged sequence corruption after standby promotion
commit : a1ed6a9a031af5d945dee498ba364cddea7af59f
author : Fujii Masao <fujii@postgresql.org>
date : Tue, 30 Jun 2026 08:50:50 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Tue, 30 Jun 2026 08:50:50 +0900 Previously, if an unlogged sequence was created on the primary and
replicated to a standby, reading the sequence after promoting the
standby (for example, with nextval()) could trigger the following
assertion failure:
TRAP: failed Assert("((const PageHeaderData *) page)->pd_special >= SizeOfPageHeaderData")
In non-assert builds, the same operation could instead fail with an
error such as:
ERROR: bad magic number in sequence
The problem was that seq_redo() updated the init fork page in shared
buffers but did not flush it to disk. During promotion,
ResetUnloggedRelations() recreates the main fork of unlogged
relations by copying the init fork from disk, bypassing shared
buffers. As a result, the main fork could be recreated from a stale
init fork instead of the WAL-replayed page.
Fix this by introducing a helper to flush init fork buffers
immediately, and make seq_redo() use it. As a result, the main fork
of an unlogged sequence is recreated from the up-to-date init fork on
disk, allowing the unlogged sequence to be read successfully after
standby promotion.
Backpatch to v15, where unlogged sequences were introduced.
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: vignesh C <vignesh21@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwH1Ssze3XM6wjoTjSLVOR041c6xP+vsdLP951=w8oG8bA@mail.gmail.com
Backpatch-through: 15 M src/backend/access/hash/hash_xlog.c
M src/backend/access/transam/xlogutils.c
M src/backend/commands/sequence.c
M src/include/access/xlogutils.h
M src/test/recovery/meson.build
A src/test/recovery/t/054_unlogged_sequence_promotion.pl
Fix handling of copy_file_range() return value
commit : 090ce6934c3442e0048192e545c05bf1c6f8d92a
author : Peter Eisentraut <peter@eisentraut.org>
date : Mon, 29 Jun 2026 11:49:11 +0200
committer: Peter Eisentraut <peter@eisentraut.org>
date : Mon, 29 Jun 2026 11:49:11 +0200 Treat copy_file_range() return value of zero as an error: it indicates
that no bytes could be copied (perhaps the source file is shorter than
expected), and the existing retry loop would otherwise spin forever
since nwritten would never reach BLCKSZ.
The other uses of copy_file_range() in the tree don't have this
problem.
Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Reviewed-by: Yingying Chen <cyy9255@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/3208cf7a-c7f3-41eb-92f6-33cbeff4df40%40eisentraut.org M src/bin/pg_combinebackup/reconstruct.c
plpython: Fix NULL pointer dereferences for broken sequence and mapping objects
commit : 3dc59c1737d288dd8d5738bdb702615017098942
author : Richard Guo <rguo@postgresql.org>
date : Mon, 29 Jun 2026 11:38:39 +0900
committer: Richard Guo <rguo@postgresql.org>
date : Mon, 29 Jun 2026 11:38:39 +0900 PL/Python and its hstore and jsonb transforms build SQL values from
Python containers by calling Python C API functions that can return
NULL, and in several places the result was used without first checking
it.
On the sequence side, PySequence_GetItem() is used when converting a
returned sequence into a SQL array or composite value, when reading
the argument list passed to plpy.execute() or plpy.cursor(), and when
reading the list of type names given to plpy.prepare(). On the
mapping side, the hstore and jsonb transforms call PyMapping_Size()
and PyMapping_Items() and then index the result with PyList_GetItem()
and PyTuple_GetItem().
All of these return NULL (or -1), with a Python exception set, for a
broken object: for example one whose __getitem__() or items() raises,
or which reports a length that disagrees with what it actually yields.
The unchecked result was then dereferenced, crashing the backend.
Fix this by checking the result of each call and reporting a regular
error if it failed, so that the underlying Python exception is
surfaced instead of taking down the session.
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49BKM9wP6m8bCXEpHwQKp7usvOGV6Jf=J7FYr_BCpxLqg@mail.gmail.com
Backpatch-through: 14 M contrib/hstore_plpython/expected/hstore_plpython.out
M contrib/hstore_plpython/hstore_plpython.c
M contrib/hstore_plpython/sql/hstore_plpython.sql
M contrib/jsonb_plpython/expected/jsonb_plpython.out
M contrib/jsonb_plpython/jsonb_plpython.c
M contrib/jsonb_plpython/sql/jsonb_plpython.sql
M src/pl/plpython/expected/plpython_composite.out
M src/pl/plpython/expected/plpython_spi.out
M src/pl/plpython/expected/plpython_types.out
M src/pl/plpython/plpy_cursorobject.c
M src/pl/plpython/plpy_spi.c
M src/pl/plpython/plpy_typeio.c
M src/pl/plpython/sql/plpython_composite.sql
M src/pl/plpython/sql/plpython_spi.sql
M src/pl/plpython/sql/plpython_types.sql
plperl: Fix NULL pointer dereference for forged array object
commit : d424d06ed2d6c6f0f11c515248a9b22e8d1a794a
author : Richard Guo <rguo@postgresql.org>
date : Wed, 24 Jun 2026 09:09:48 +0900
committer: Richard Guo <rguo@postgresql.org>
date : Wed, 24 Jun 2026 09:09:48 +0900 In get_perl_array_ref(), for a PostgreSQL::InServer::ARRAY object, we
look up its "array" key with hv_fetch_string() and then inspect the
returned SV. However, hv_fetch_string() returns a NULL pointer when
the key is absent, and the code dereferenced that result without first
checking whether the pointer itself was NULL. As a result, a plperl
function returning a forged PostgreSQL::InServer::ARRAY object that
lacks the "array" key would crash the backend with a segmentation
fault.
Fix this by checking the pointer returned by hv_fetch_string() before
dereferencing it, matching how other callers in this file already
guard the result. With the check in place, such an object falls
through to the existing error report instead of crashing.
Author: Xing Guo <higuoxing@gmail.com>
Reviewed-by: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CACpMh+DYgcnqZwQLXXuxQcehJTd7T8UmKWSLsK4mFBEp9G2ajA@mail.gmail.com
Backpatch-through: 14 M src/pl/plperl/expected/plperl_array.out
M src/pl/plperl/plperl.c
M src/pl/plperl/sql/plperl_array.sql
doc: Describe better handling of indexes in ALTER TABLE ATTACH PARTITION
commit : f67b9dd8fc70f0742cf91d5796ccef630ba71d9b
author : Michael Paquier <michael@paquier.xyz>
date : Tue, 23 Jun 2026 16:52:16 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Tue, 23 Jun 2026 16:52:16 +0900 When ALTER TABLE ... ATTACH PARTITION matches partition indexes to the
parent table's indexes, invalid indexes are skipped. This commit
improves the documentation to describe what e90e9275f56 has changed:
invalid indexes are skipped, and only valid indexes are considered for a
match.
Author: Mohamed Ali <moali.pg@gmail.com>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Discussion: https://postgr.es/m/CAGnOmWpAMaE-BOkpwM6mJnHcpS2QZ8yLSSaqmz+vryEsbCWWWA@mail.gmail.com
Backpatch-through: 14 M doc/src/sgml/ref/alter_table.sgml
Re-introduce pgstat_drop_entry(), keeping ABI compatibility
commit : afb076b2977c39efec873cde2dceacd97be243a6
author : Michael Paquier <michael@paquier.xyz>
date : Tue, 23 Jun 2026 07:59:00 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Tue, 23 Jun 2026 07:59:00 +0900 This routine acts as a wrapper of a new pgstat_drop_entry_ext(), used in
the core code with a missing_ok argument.
This includes an update of .abi-compliance-history, removing the latest
entry that has documented the change of pgstat_drop_entry(). This
change is applied across v15~v18. HEAD keeps pgstat_drop_entry() as
single entry point, with the new missing_ok.
Per discussion with Álvaro Herrera and Lukas Fittl. This is a follow-up
of 850b9218c8e4.
Discussion: https://postgr.es/m/ajZz_sVJVX7pmPHo@alvherre.pgsql
Backpatch-through: 15-18 M .abi-compliance-history
M src/backend/utils/activity/pgstat_function.c
M src/backend/utils/activity/pgstat_replslot.c
M src/backend/utils/activity/pgstat_shmem.c
M src/backend/utils/activity/pgstat_xact.c
M src/include/utils/pgstat_internal.h
Fix unsafe order of operations in ResourceOwnerReleaseAll().
commit : 011eedcdc3fe04000c46881333aaa0ac70a1aa1f
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 22 Jun 2026 18:03:23 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 22 Jun 2026 18:03:23 -0400 This function called the resource-kind-specific ReleaseResource()
method for each item before deleting that item from the resowner.
That's backwards from the ordering in ResourceOwnerReleaseAllOfKind,
and it's not very safe. If ReleaseResource throws an error then the
subsequent abort cleanup will come back here and try to release that
item again, possibly leading to a double-free or similar crash,
and in any case risking an infinite error cleanup loop. This mistake
explains why the pgcrypto bug just fixed in 80bb0ebcc led to a crash
rather than something more benign.
Remove the item from the resowner, then call ReleaseResource,
matching the way things were done before b8bff07da. If there
is a problem of this sort, we'd prefer to leak the item than
suffer the other likely consequences.
Per further analysis of bug #19527.
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/646741.1782157515@sss.pgh.pa.us
Backpatch-through: 17 M src/backend/utils/resowner/resowner.c
pgcrypto: avoid recursive ResourceOwnerForget().
commit : 2aa6be6e64812ab3421b506c20b0e15078160e75
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 22 Jun 2026 12:59:16 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 22 Jun 2026 12:59:16 -0400 Raising an error within a function using an OSSLCipher object led
to a complaint from ResourceOwnerForget and then a double-free crash,
because ResOwnerReleaseOSSLCipher forgot to unhook the OSSLCipher
object from its owner. (The sibling logic for OSSLDigest objects got
this right, as did every other ReleaseResource function AFAICS.)
Oversight in cd694f60d.
Bug: #19527
Reported-by: Yuelin Wang <3020001251@tju.edu.cn>
Author: Yuelin Wang <3020001251@tju.edu.cn>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19527-6e7686960c6dce78@postgresql.org
Backpatch-through: 17 M contrib/pgcrypto/openssl.c
Make pg_mkdir_p() tolerant of a concurrent directory creation.
commit : f0a831ef3e68d64520ca3543424c49dca7f7aa95
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Fri, 19 Jun 2026 12:52:00 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Fri, 19 Jun 2026 12:52:00 -0400 pg_mkdir_p creates each missing path component with a stat() followed
by mkdir(). If the stat() reports the component as absent but another
process creates it in the window before this process's mkdir(), mkdir()
fails with EEXIST and pg_mkdir_p treated that as a hard error -- unlike
"mkdir -p", which is meant to be idempotent and race-tolerant.
This shows up when several processes concurrently create paths that
share an ancestor directory: for example, parallel initdb runs whose
data directories live under a common temporary directory. One process
wins the race to create the shared ancestor and the others fail with
could not create directory "...": File exists
Fix this race condition by first trying mkdir() and only attempting
stat() if it fails with EEXIST.
On Windows, there's an additional problem: stat() opens a file handle
and participates in share-mode locking, which means it can transiently
fail on a directory another process is concurrently creating. Use
GetFileAttributes() instead: it requests only FILE_READ_ATTRIBUTES
and is exempt from share-mode denial, so it reliably sees a
concurrently-created directory.
I (tgl) also chose to back-patch 039f7ee0f's effects on this function,
so that pgmkdirp.c remains identical in all live branches.
Author: Andrew Dunstan <andrew@dunslane.net>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/3ca004de-e49b-4471-b8aa-fd656e70f68c@dunslane.net
Backpatch-through: 14 M src/port/pgmkdirp.c
Silence "may be used uninitialized" compiler warning.
commit : 7fbbe75875ca510c4fe730c2ecbb48bf54001574
author : Nathan Bossart <nathan@postgresql.org>
date : Thu, 18 Jun 2026 11:29:49 -0500
committer: Nathan Bossart <nathan@postgresql.org>
date : Thu, 18 Jun 2026 11:29:49 -0500 Newer gcc warns that this "actual_arg_types" variable may be used
uninitialized, but visual inspection indicates there's no bug. To
silence the warning, initialize the variable to zeros.
Bug: #19485
Reported-by: Hans Buschmann <buschmann@nidsa.net>
Tested-by: Erik Rijkers <er@xs4all.nl>
Tested-by: Hans Buschmann <buschmann@nidsa.net>
Reviewed-by: Tristan Partin <tristan@partin.io>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/19485-2b03231a775756f1%40postgresql.org
Discussion: https://postgr.es/m/6c52a1a6612948519468d46cb224a8c4%40nidsa.net M src/backend/optimizer/util/clauses.c
hstore_plperl: Add CHECK_FOR_INTERRUPTS() in reference-unwinding loop.
commit : 4efef9d18e637f5d1e9e09129785d73f5f8619b4
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Thu, 18 Jun 2026 12:22:55 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Thu, 18 Jun 2026 12:22:55 -0400 Add CHECK_FOR_INTERRUPTS() to the while loop in plperl_to_hstore()
that dereferences chains of Perl references, so that a circular
reference (e.g. $x = \$x) can be cancelled by the user instead of
spinning indefinitely. (We looked at detecting such circular
references, but it seems more trouble than it's worth.)
This is a follow-up to da82fbb8f, which fixed the same issue in
SV_to_JsonbValue() in jsonb_plperl.
Author: Aleksander Alekseev <aleksander@tigerdata.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAJ7c6TPbjkzUk4qJ5dHvDNEz0hBuFue3A-XWz_=897z+BC+z8A@mail.gmail.com
Backpatch-through: 14 M contrib/hstore_plperl/hstore_plperl.c
doc: Fix "Prev" link, take 2.
commit : 1fec5ddfdc2d39188cde6cd6494c5e1f9d0a9ddd
author : Nathan Bossart <nathan@postgresql.org>
date : Thu, 18 Jun 2026 09:31:27 -0500
committer: Nathan Bossart <nathan@postgresql.org>
date : Thu, 18 Jun 2026 09:31:27 -0500 Commit 6678b58d78 fixed a wrong "Prev" link by changing the link
generation code to use [position()=last()] instead of [last()] in
the predicate on the union of reverse axes. Unfortunately, that
caused documentation builds to take much longer. To fix, combine
the "preceding" and "ancestor" steps into one "preceding" step and
one "ancestor" step, and revert the predicate back to [last()].
The smaller union evades the libxml2 bug while avoiding the build
time regression.
Reported-by: Tom Lane <tgl@sss.pgh.pa.us>
Tested-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/1132496.1781718007%40sss.pgh.pa.us
Backpatch-through: 14 M doc/src/sgml/stylesheet-speedup-xhtml.xsl
Update .abi-compliance-history for pgstat_drop_entry()
commit : 39e649d44a1db44cabbff43047f257cba213261e
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 18 Jun 2026 14:48:40 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 18 Jun 2026 14:48:40 +0900 As noted in the commit message of 850b9218c8e4, this function has gained
an extra called "missing_ok". All the callers of this routine should be
in core in the v15-v17 range. For v18, I have found one custom stats
kind that would be impacted by this change.
Discussion: https://postgr.es/m/ajOE3uRxVgSlPRcw@paquier.xyz
Backpatch-through: 15-18 M .abi-compliance-history
Avoid stale slot access after dropping obsolete synced slots.
commit : ea834d747d454c4fd66b08ebecaa9483476cf4a4
author : Amit Kapila <akapila@postgresql.org>
date : Thu, 18 Jun 2026 09:35:53 +0530
committer: Amit Kapila <akapila@postgresql.org>
date : Thu, 18 Jun 2026 09:35:53 +0530 drop_local_obsolete_slots() continued to dereference local_slot after
calling ReplicationSlotDropAcquired(). Once the slot is dropped, its
entry in the slot array can be reused by another backend, so later reads
of local_slot->data could observe a different slot's name or database
OID, leading to an incorrect unlock and log message.
Save the slot name and database OID before performing the drop, and use
the saved values for the subsequent UnlockSharedObject() call and the log
message. While at it, emit the "dropped replication slot" message only
when a slot was actually dropped, rather than unconditionally.
Author: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Backpatch-through: 17, where it was introduced
Discussion: https://postgr.es/m/TY4PR01MB177184FF9EE916F577E1F554194082@TY4PR01MB17718.jpnprd01.prod.outlook.com M src/backend/replication/logical/slotsync.c
Fix PANIC with track_functions due to concurrent drop of pgstats entries
commit : 2e0c61aed6241bb66547bfab7467d43f889f78ba
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 18 Jun 2026 11:49:36 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 18 Jun 2026 11:49:36 +0900 pgstat_drop_entry_internal() generates an ERROR if facing a pgstats
entry already marked as dropped. With a workload doing a lot of
concurrent CALL and DROP/CREATE PROCEDURE, it could be possible for
AtEOXact_PgStat_DroppedStats(), that wants to do transactional drops, to
find entries that are already dropped, after a commit record has been
written. In this case, ERRORs are upgraded to PANIC, taking down the
server.
This issue is fixed by making pgstat_drop_entry() optionally more
tolerant to concurrent drops, adding to the routine a missing_ok option
to make some of its callers more tolerant (spoiler: some of the callers
want a strict behavior, like replication slots and backend stats).
pgstat_drop_entry_internal() cannot be called anymore for an entry
marked as dropped, hence its error is replaced by an assertion.
Functions are handled as a special case in core; this problem could also
apply to custom stats kinds depending on what an extension does.
track_functions is costly when enabled (disabled by default), which is
perhaps the main reason why this has not be found yet.
A similar version of this patch has been proposed by Sami Imseih on a
different thread for a feature in development. This version has tweaked
here by me for the sake of fixing this issue.
Reported-by: zhanglihui <zlh21343@163.com>
Author: Sami Imseih <samimseih@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/19520-73873648d44793cf@postgresql.org
Backpatch-through: 15 M src/backend/utils/activity/pgstat_function.c
M src/backend/utils/activity/pgstat_replslot.c
M src/backend/utils/activity/pgstat_shmem.c
M src/backend/utils/activity/pgstat_xact.c
M src/include/utils/pgstat_internal.h
jsonb_plperl, jsonb_plpython: Fix unguarded recursion and loops.
commit : 3df0b77558d790b72103379555cd406101e9abcb
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Wed, 17 Jun 2026 11:04:41 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Wed, 17 Jun 2026 11:04:41 -0400 Add check_stack_depth() to Jsonb_to_SV, SV_to_JsonbValue,
PLyObject_FromJsonbContainer, and PLyObject_ToJsonbValue. Without
this, deeply nested JSONB values can crash the backend with SIGSEGV
instead of raising a proper error.
Also add CHECK_FOR_INTERRUPTS() to the while loop in SV_to_JsonbValue
that dereferences chains of Perl references, so that a circular
reference (e.g. $x = \$x) can be cancelled by the user instead of
spinning indefinitely. (We looked at detecting such circular
references, but it seems more trouble than it's worth.)
Author: Aleksander Alekseev <aleksander@tigerdata.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAJ7c6TPbjkzUk4qJ5dHvDNEz0hBuFue3A-XWz_=897z+BC+z8A@mail.gmail.com
Backpatch-through: 14 M contrib/jsonb_plperl/jsonb_plperl.c
M contrib/jsonb_plpython/jsonb_plpython.c
Fix another instability in recovery TAP test 004_timeline_switch
commit : 3afabab78d2566a9c9d1761f1d152b550ff83566
author : Michael Paquier <michael@paquier.xyz>
date : Wed, 17 Jun 2026 08:42:09 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Wed, 17 Jun 2026 08:42:09 +0900 The test did not wait for the standby to be connected to the primary.
This breaks one assumption at the beginning of the test, where the
primary is stopped to ensure that all its records are flushed to both
standbys before moving on with its next steps.
If standby_1 finishes ahead of standby_2, the test would be able work
fine as the former waits for the latter. The opposite is not true,
standby_2 getting ahead of standby_1 would cause the test to fail on
timeout when standby_1 attempts to connect to standby_2.
This commit adds an additional polling query after the two standbys are
started, checking that both standbys are connected to the primary before
processing with the initial steps of the test.
Like 7185eddf0522, backpatch down to v14.
Author: Sergey Tatarintsev <s.tatarintsev@postgrespro.ru>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Discussion: https://postgr.es/m/fea4190e-f8b5-4432-a52d-bcbee5f34366@postgrespro.ru
Backpatch-through: 14 M src/test/recovery/t/004_timeline_switch.pl
logical decoding: Correctly free speculative insertion
commit : ac445069002c9e8c91878c2ce04d4e6a12398fc6
author : Álvaro Herrera <alvherre@kurilemu.de>
date : Tue, 16 Jun 2026 18:13:15 +0200
committer: Álvaro Herrera <alvherre@kurilemu.de>
date : Tue, 16 Jun 2026 18:13:15 +0200 The error path in ReorderBufferProcessTXN was not freeing
(reorderbuffer.c's representation of) a speculative insertion record
correctly. In assert-enabled builds, this leads to an assertion
failure. In production builds, I see no effect; there may be a small
transient leak, but in an improbable code path such as this, such a leak
is not of any significance. For users running with assertions enabled,
the crash is annoying.
Fix by having ReorderBufferProcessTXN() free the speculative insert
ahead of freeing the rest of the transaction, and no longer try to
handle that insert as a separate argument to ReorderBufferResetTXN().
This code came in with commit 7259736a6e5b (14-era). Backpatch all the
way back.
In branches 14-16, also backpatch the assertion that originally fails in
the problem scenario, which was added by dbed2e36625d (originally
backpatched to 17), that at the end of ReorderBufferReturnTXN() the
in-memory size of the transaction is zero.
Author: Vishal Prasanna <vishal.g@zohocorp.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Backpatch-through: 14
Discussion: https://postgr.es/m/19c7623e882.4080fd5426212.311756747309556767@zohocorp.com M src/backend/replication/logical/reorderbuffer.c
M src/test/subscription/t/100_bugs.pl
Fix int32 overflow in ltree_compare()
commit : c391c00d9dd792e7f8d385ea05400c50eca82d78
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 16 Jun 2026 09:27:00 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Tue, 16 Jun 2026 09:27:00 +0300 The expression (len_diff * 10 * (an + 1)) used as the return value of
ltree_compare() is computed at int32 width. With LTREE_MAX_LEVELS =
65535, the product can exceed INT32_MAX once an ltree has more than
~14,653 levels, which causes the result to wrap and invert its sign.
That corrupts btree ordering as well as the "magnitude" consumed by
ltree_penalty() for GiST page splits.
To fix, split ltree_compare() into two functions. The new
ltree_compare_distance() function returns a float, which won't
overflow. It's used by the ltree_penalty() caller. All the other
callers only care about the sign of the return value, i.e. which of
the arguments is greater, so change ltree_compare() to not multiply
the result with (10 * (an + 1)), which avoids the overflow for those
callers.
Existing btree or GiST indexes on ltree columns containing values with
more than ~14,653 levels may be corrupt and should be REINDEXed.
Add a regression test based on the reporter's PoC.
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reported-by: 王跃林 <violin0613@tju.edu.cn>
Discussion: https://www.postgresql.org/message-id/AI6AnABgKW93Qbx1jVzi84r9.8.1781322625756.Hmail.3020001251%40tju.edu.cn
Backpatch-through: 14 M contrib/ltree/expected/ltree.out
M contrib/ltree/ltree.h
M contrib/ltree/ltree_gist.c
M contrib/ltree/ltree_op.c
M contrib/ltree/sql/ltree.sql
Clean up quoting of variable strings within replication commands.
commit : 14810cc0d96c9338dbadbfecf08b26b20cd4113d
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 15 Jun 2026 15:35:37 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 15 Jun 2026 15:35:37 -0400 Our handling of quoting within replication commands was pretty
sloppy, typically looking like
appendStringInfo(&cmd, " SLOT \"%s\"", options->slotname);
This is fine as long as options->slotname doesn't contain a double
quote mark, but what if it does? In principle this'd allow injection
of harmful options into replication commands, in the probably-unlikely
case that a slot name comes from untrustworthy input. We ought to
clean that up.
Moreover, even the places that were trying to be more careful
generally got it wrong, because they used quoting subroutines
intended for SQL commands rather than something that will work
with the replication-command scanner repl_scanner.l. For example,
several places naively use PQescapeLiteral() to quote option values
for replication commands. If the string contains a backslash,
PQescapeLiteral() will produce E'...' literal syntax, which
repl_scanner.l doesn't recognize. Another near miss was to use
quote_identifier() to quote identifiers. That function won't quote
valid lowercase identifiers unless they match SQL keywords ... but in
this context, replication keywords are what matter. Neither of these
errors seem to risk string injection, but they definitely can cause
syntax errors in replication commands that ought to be valid.
We can clean all this up by using simple quoting logic that just
doubles single or double quotes respectively.
Or at least, we could if repl_scanner.l handled doubled double quotes
in identifiers, but for some reason it doesn't! So the first step in
this fix has to be to fix that. (The fact that we'll later reject
slot names containing double quotes is very far short of justifying
this omission.)
Having done that, this patch runs around and applies correct
quoting in all places that generate replication commands containing
strings coming from outside the immediate context. Probably some
of these places are safe because of restrictions elsewhere, but it
seems best to just quote all the time.
This was originally reported as a security bug, which it could be
if replication slot names or parameters were to originate from
untrustworthy sources. But the security team concluded that that
was a very improbable situation, so we're just going to fix this
as a regular bug.
Reported-by: Team Dhiutsa
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/1648659.1781287310@sss.pgh.pa.us
Backpatch-through: 14 M src/backend/commands/subscriptioncmds.c
M src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
M src/backend/replication/repl_scanner.l
M src/bin/pg_basebackup/pg_recvlogical.c
M src/bin/pg_basebackup/receivelog.c
M src/bin/pg_basebackup/streamutil.c
M src/bin/pg_basebackup/streamutil.h
doc: Fix "Prev" link.
commit : 1c4ba21685cb3b5834408826fec7ad427382d9bd
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 15 Jun 2026 12:16:38 -0500
committer: Nathan Bossart <nathan@postgresql.org>
date : Mon, 15 Jun 2026 12:16:38 -0500 Presently, the "Prev" link on the page for background workers sends
you to the middle of the previous chapter instead of the actual
previous page. This appears to be caused by a libxml2 bug, but
regardless, a minimal fix is to change the link generation code to
use [position()=last()] instead of [last()] in the predicate on the
union of reverse axes.
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/aim4AZorFKaC7Wrf%40nathan
Backpatch-through: 14 M doc/src/sgml/stylesheet-speedup-xhtml.xsl
Modernize pg_bsd_indent's error/warning reporting code.
commit : 293de33ae5d098e4f77113fc89d741a19003f7b7
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 15 Jun 2026 12:22:55 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 15 Jun 2026 12:22:55 -0400 Late-model clang complains that these functions should be labeled
with "format(printf, 2, 3)", and it's right. But let's go a bit
further and also make use of varargs, to remove duplication and
allow these functions to be used with non-integer input values.
Since no good deed goes unpunished, I had to also adjust a couple
of call sites. They weren't wrong as-is, since the size_t-sized
arguments were coerced to int on the way into diag3(). But
without that, we have to adjust the format strings.
The point of this is to suppress compiler warnings, so back-patch
into branches containing pg_bsd_indent, even though there's no
functional change.
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/1645041.1781283554@sss.pgh.pa.us
Backpatch-through: 16 M src/tools/pg_bsd_indent/indent.c
M src/tools/pg_bsd_indent/indent.h
M src/tools/pg_bsd_indent/io.c
Fix PQdescribePrepared with more than 7498 params
commit : e4183c667d86c365c3e93e2f687d416e375aeb8a
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Mon, 15 Jun 2026 11:28:45 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Mon, 15 Jun 2026 11:28:45 +0300 If a query has more than 7498 params, the ParameterDescription message
exceeds the 30000 byte limit on messages that are not specifically
marked as possibly being longer than that (VALID_LONG_MESSAGE_TYPE).
To fix, add ParameterDescription to the list.
Author: Ning Sun <classicning@gmail.com>
Discussion: https://www.postgresql.org/message-id/dbfb4b65-0aa8-470a-8b87-b6496160b28a@gmail.com
Backpatch-through: 14 M src/interfaces/libpq/fe-protocol3.c
Trim regression test expected output for xml
commit : 3928b7a520e3f2ffec26d644d60a467ac7558578
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 15 Jun 2026 11:37:57 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Mon, 15 Jun 2026 11:37:57 +0900 This commit reduces the number of expected output files for the "xml"
test from three to two (well, mostly one, see below for details).
xml_2.out existed to handle some differences in output due to libxml2
2.9.3, due to some error context missing (085423e3e326). This file is
removed, by tweaking the XML inputs to trigger the same error patterns
for the problematic 2.9.3 and other libxml2 versions. This part is
authored by Tom Lane.
xml_1.out (no libxml2 support) is reduced in size by adding an \if query
that exits the test early. This still checks NO_XML_SUPPORT() through
xmlin(). The rest of the test is skipped if XML input cannot be
handled by the backend. This part has been written by me.
Author: Tom Lane <tgl@sss.pgh.pa.us>
Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/aiu6CXO67q-s70n5@paquier.xyz
Backpatch-through: 14 M src/test/regress/expected/xml.out
M src/test/regress/expected/xml_1.out
D src/test/regress/expected/xml_2.out
M src/test/regress/sql/xml.sql
Doc: remove stale entry for removed aclitem[] ~ aclitem operator.
commit : 6e49974e86d3f183d74bfedd5e91a4f7d48d3e1b
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 14 Jun 2026 11:01:48 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Sun, 14 Jun 2026 11:01:48 -0400 Commit 2f70fdb06 removed the deprecated containment operator
~(aclitem[],aclitem) from the catalogs, but missed removing its entry
from the documentation. (Arguably the blame should fall on c62dd80cd,
which added this entry in contravention of the longstanding policy
that we don't document deprecated aliases in the first place.)
Author: Shinya Kato <shinya11.kato@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAOzEurQSyR5psWukyhUz1LtxyO55C2Vfp0Fmt8w2jGKxhszQmQ@mail.gmail.com
Backpatch-through: 14 M doc/src/sgml/func.sgml
amcheck: Use correct varlena size accessor in bt_normalize_tuple()
commit : 8abb8a1555f4051491eced0307adf218e0f9f34e
author : Alexander Korotkov <akorotkov@postgresql.org>
date : Sun, 14 Jun 2026 02:49:05 +0300
committer: Alexander Korotkov <akorotkov@postgresql.org>
date : Sun, 14 Jun 2026 02:49:05 +0300 bt_normalize_tuple() uses VARSIZE() to get the size of varlena, even though
it's not yet known, that it has a 4-byte header. Fix this by replacing a
accessor with a universal VARSIZE_ANY().
Backpatch to all supported versions.
Reported-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/7ckc7oka4bvafkf5bwlqs6ygrhlsbhz25ppozfch7zbuxcx3rf%40e4pr4oqenalc
Author: Andrey Borodin <x4mmm@yandex-team.ru>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Backpatch-through: 14 M contrib/amcheck/verify_nbtree.c
Adjust cross-version upgrade tests for seg_out() fix
commit : c0d44e00940672c55c56344f4f3b3ed16b555b01
author : Andrew Dunstan <andrew@dunslane.net>
date : Fri, 12 Jun 2026 18:05:25 -0400
committer: Andrew Dunstan <andrew@dunslane.net>
date : Fri, 12 Jun 2026 18:05:25 -0400 Commit 0e1f1ed157e taught seg_out() to print the certainty indicator
on an interval's upper boundary, but it was back-patched only as far
as v14. When upgrading from an older release, the old server prints
the one test_seg row exercising that case ('4.6 .. ~7.0') without the
indicator, so the pre- and post-upgrade dumps do not match. Make
AdjustUpgrade.pm delete just that row; seg's comparison function does
distinguish the certainty indicators, so the otherwise identical row
'4.6 .. 7.0' is unaffected.
Back-patch to all supported branches.
Per buildfarm members crake and fairywren.
Discussion: https://postgr.es/m/5ccbdbde-6467-4a10-bf4d-0be73a05ce8d@dunslane.net M src/test/perl/PostgreSQL/Test/AdjustUpgrade.pm
Fix compilation with OpenSSL 4
commit : 8bcabfccea32b9ed169312163b116a2b8f320f5c
author : Daniel Gustafsson <dgustafsson@postgresql.org>
date : Fri, 12 Jun 2026 13:57:22 +0200
committer: Daniel Gustafsson <dgustafsson@postgresql.org>
date : Fri, 12 Jun 2026 13:57:22 +0200 OpenSSL 4.0.0 changed some parameters and returnvalues to const, so
we need to update our declarations and subsequently cast away const-
ness from a few callsites to make libpq build without warnings. This
is tested with OpenSSL 1.1.1 through 4.0.0 as well as with LibreSSL.
No functional change is introduced, this commit only allows postgres
to be compiled against OpenSSL 4.0.0 without warnings.
There is also an errormessage change in OpenSSL 4.0.0 which needed
to be covered by our testharness.
This will be backpatched to all supported branches since they are
all equally likely to be built against OpenSSL 4.0.0 as it becomes
available in distributions. Backpatching will be done once it has
been in master for a few days without issues.
Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/066B07BB-85FA-487C-BE8C-40F791CFC3C4@yesql.se
Backpatch-through: 14 M contrib/sslinfo/sslinfo.c
M src/backend/libpq/be-secure-openssl.c
M src/interfaces/libpq/fe-secure-openssl.c
M src/test/ssl/t/001_ssltests.pl
Update expected regression test output for xml_2.out
commit : 940916549baab4c7d48cc4a6047c7c540f39586b
author : Michael Paquier <michael@paquier.xyz>
date : Fri, 12 Jun 2026 12:37:21 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Fri, 12 Jun 2026 12:37:21 +0900 This one has been forgotten in 8bf257aebac1. Per report from buildfarm
member massasauga.
Backpatch-through: 14 M src/test/regress/expected/xml_2.out
Fix second race with timeline selection during promotion
commit : ab5334d8bfa29737c3e5117c847c28f6f39d1743
author : Michael Paquier <michael@paquier.xyz>
date : Fri, 12 Jun 2026 11:44:16 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Fri, 12 Jun 2026 11:44:16 +0900 read_local_xlog_page_guts has the same race as logical_read_xlog_page:
RecoveryInProgress() can return true during promotion, impacting the
availability of the operations doing WAL page reads with this callback.
This problem is similar to eb4e7224a1c6 that has addressed the issue for
logical replication, impacting more areas of the code where this WAL
page callback can be used (same narrow window during promotion, same
availability issue):
- pg_walinspect.
- Slot advance (SQL function).
- Slot creation.
Repack workers (v19~) and 2PC files (since forever) can also use this
callback, but they are irrelevant as far as I know. A test is added
with the SQL lookup functions. This part relies on injection points,
and is backpatched down to v18, like the test added for eb4e7224a1c6.
This issue could probably be fixed as well in v14 and v15 for
pg_walinspect. However, I also feel that there is a conservative
argument about consistency here due to the support of logical decoding
on standbys, so let's limit ourselves to v16 for now. pg_walinspect is
used less in the field compared to the two other operations, making
addressing this problem less attractive in these two older branches.
Reported-by: Xuneng Zhou <xunengzhou@gmail.com>
Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3%40gmail.com
Backpatch-through: 16 M src/backend/access/transam/xlogutils.c
doc: fix reference for finding replication slots to drop
commit : e90251176da4fb0a6ffed01b5aaff9621b93cf4d
author : Fujii Masao <fujii@postgresql.org>
date : Fri, 12 Jun 2026 11:08:33 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Fri, 12 Jun 2026 11:08:33 +0900 Commit a70bce43fb added instructions on how to recover if PostgreSQL
refuses to issue new transaction IDs because of imminent wraparound,
but when describing how to find replication slots that should be dropped,
it referred to pg_stat_replication where it should have referenced
pg_replication_slots.
In passing, decorate references to views with <structname> tags.
Backpatch to all supported versions.
Reported-By: Sanjaya Waruna <sanjaya.waruna@gmail.com>
Author: Laurenz Albe <laurenz.albe@cybertec.at>
Reviewed-by: Robert Treat <rob@xzilla.net>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/176767268098.1084085.10345048667224193115@wrigleys.postgresql.org
Backpatch-through: 14 M doc/src/sgml/maintenance.sgml
Fix handling of namespace nodes in xpath() (xml)
commit : 6c08cbb7a7b45171f058641c553210cd3261fe6c
author : Michael Paquier <michael@paquier.xyz>
date : Fri, 12 Jun 2026 10:25:51 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Fri, 12 Jun 2026 10:25:51 +0900 xpath() attempted to call xmlCopyNode() and xmlNodeDump() on a
XML_NAMESPACE_DECL, finishing with a confusing error:
=# SELECT xpath('//namespace::foo', '<root xmlns:foo="http://127.0.0.1"/>');
ERROR: 53200: could not copy node
CONTEXT: SQL function "xpath" statement 1
xpath() is changed so as it goes through xmlXPathCastNodeToString()
instead, that is able to handle namespace nodes. xml2 uses the same
solution. This issue has been discovered while digging into
9d33a5a804db.
Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/aioT7ui_ZJ9RMlfM@paquier.xyz
Backpatch-through: 14 M src/backend/utils/adt/xml.c
M src/test/regress/expected/xml.out
M src/test/regress/expected/xml_1.out
M src/test/regress/sql/xml.sql
IS JSON/JSON(): Protect against expressions uncoercible to text
commit : d0acd2535b4adb21ad952d12e0f8c3fb25999d28
author : Álvaro Herrera <alvherre@kurilemu.de>
date : Thu, 11 Jun 2026 16:17:58 +0200
committer: Álvaro Herrera <alvherre@kurilemu.de>
date : Thu, 11 Jun 2026 16:17:58 +0200 transformJsonParseArg() was not careful enough on generation of
transformed expressions when starting from expressions that are not
coercible to text but are in the string type category: it failed to
verify that coerce_to_target_type() succeeds, and returned a NULL
pointer. This leads to a later NULL dereference and crash at executor
time.
This escaped noticed because it cannot happen for built-in types, all of
which have casts to text. Only user-created types are potentially
problematic.
Fix by raising an error when a cast to text doesn't exist.
This mistake came in with commit 6ee30209a6f1.
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reported-by: Chi Zhang <798604270@qq.com>
Reviewed-by: Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Backpatch-through: 16
Discussion: https://postgr.es/m/19491-7aafc221ec63f288@postgresql.org M src/backend/nodes/makefuncs.c
M src/backend/parser/parse_expr.c
M src/test/regress/expected/sqljson.out
M src/test/regress/sql/sqljson.sql
Remove TAP test for timeline lookup race with logical decoding on standbys
commit : c011d5b654573db9e2db7cf2eb4e62e58bd2aa86
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 11 Jun 2026 19:00:55 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 11 Jun 2026 19:00:55 +0900 16b89ff04839 has introduced this test, but I have missed that the script
should check for the existence of the test module injection_points.
This requirement has been added by 105b2cb33617 in v18 and newer
branches.
Let's just remove the test on v17. There is still coverage in v18 and
HEAD, that should be good enough.
Per reports from the buildfarm.
Discussion: https://postgr.es/m/aiqFjzGHpnYFP-Gm@paquier.xyz
Backpatch-through: 17 (only) M src/backend/access/transam/xlog.c
M src/test/recovery/t/035_standby_logical_decoding.pl
seg: Fix seg_out() to preserve the upper boundary's certainty indicator
commit : bcbbd070d4961aa4c2f983bdbcf488c0c0d752a1
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 11 Jun 2026 12:33:48 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 11 Jun 2026 12:33:48 +0300 When printing the upper boundary of a seg interval, seg_out() decided
whether to emit the certainty indicator ('<', '>' or '~') by testing the
upper indicator (u_ext) for '<' and '>', but mistakenly tested the lower
indicator (l_ext) for '~'. This is a copy-and-paste slip from the
symmetric code that prints the lower boundary a few lines above.
The consequences for valid input were:
* A '~' on the upper boundary was dropped on output, e.g.
'1.5 .. ~2.5'::seg printed as '1.5 .. 2.5'.
* When the lower boundary carried '~' but the upper boundary had no
indicator, the wrong test matched and sprintf(p, "%c", seg->u_ext)
wrote a NUL byte (u_ext == '\0'), which truncated the result string
and silently lost the entire upper boundary, e.g.
'~6.5 .. 8.5'::seg printed as '~6.5 .. '.
Certainty indicators are documented to be preserved on output (they are
ignored by the operators, but kept as comments), so this broke the
input/output round-trip for the affected values.
The bug has existed since seg was added. It went unnoticed because the
existing regression tests only exercised certainty indicators on
single-point segs, which are printed by a different branch of seg_out().
Add tests that place indicators on both boundaries of an interval.
Author: Ewan Young <kdbase.hack@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAON2xHPYeRRCEVAv8XfE18KsEsEHCiYcJ5fOsoxFuMEfpxF1=g@mail.gmail.com
Backpatch-through: 14 M contrib/seg/expected/seg.out
M contrib/seg/seg.c
M contrib/seg/sql/seg.sql
Fix race with timeline selection in logical decoding during promotion
commit : 16b89ff048391c7f1bb4758de203c82c1a6dd7b8
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 11 Jun 2026 17:29:39 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 11 Jun 2026 17:29:39 +0900 During promotion, there is a window where RecoveryInProgress() returns
true but the WAL segments of the old timeline have already been removed.
A logical decoding could pick up the old timeline in this window when
reading a page, failing with the following error:
ERROR: requested WAL segment ... has already been removed
This issue does not lead to any data correctness issue, as retrying to
decode the data works in follow-up decoding attempts. It impacts
availability, though. Other WAL page read callbacks have a similar
issue, this commit takes care of what should be the noisiest code path:
logical decoding with START_REPLICATION in a WAL sender.
A TAP test, based on an injection point waiting in the startup process
after the segments have been removed/recycled, is added. This part is
backpatched down to v17.
This issue has been causing sporadic failures in the buildfarm, and
was reproducible manually. This issue happens since logical decoding on
standbys exists, down to v16.
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/7daef094-abf3-4672-bc23-3df4763b16a3@gmail.com
Backpatch-through: 16 M src/backend/access/transam/xlog.c
M src/backend/replication/walsender.c
M src/test/recovery/t/035_standby_logical_decoding.pl
xml2: Fix crash with namespace nodes in xpath_nodeset()
commit : 4a49ab2890859c62dd49959b0f6cfbbd516b8310
author : Michael Paquier <michael@paquier.xyz>
date : Thu, 11 Jun 2026 14:29:24 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Thu, 11 Jun 2026 14:29:24 +0900 pgxmlNodeSetToText() passed nodeTab[i]->doc to xmlNodeDump() without
checking the node type, which could cause a crash as a
XML_NAMESPACE_DECL maps to a xmlNs struct. The passed-in code would
then be dereferenced in xmlNodeDump().
This commit switches the code to render XML_NAMESPACE_DECL nodes with
xmlXPathCastNodeToString(), like xpath_table(). Some tests are added,
written by me.
Author: Andrey Chernyy <andrey.cherny@tantorlabs.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/20260611031436.5afde3cb@andrnote
Backpatch-through: 14 M contrib/xml2/expected/xml2.out
M contrib/xml2/expected/xml2_1.out
M contrib/xml2/sql/xml2.sql
M contrib/xml2/xpath.c
Use correct type for catalog_xmin
commit : 9db452c2355092ce28fb5b62b9541779ff7fe601
author : Fujii Masao <fujii@postgresql.org>
date : Tue, 9 Jun 2026 08:18:41 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Tue, 9 Jun 2026 08:18:41 +0900 Commit 85c17f6 mistakenly declared a variable storing catalog_xmin as
XLogRecPtr, even though catalog_xmin is a TransactionId.
This caused no functional issue, but the type was clearly incorrect.
Therefore, this commit fixes it to use the correct type TransactionId
instead, and backpatch to v17 where the issue was introduced.
Author: Imran Zaheer <imran.zhir@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CA+UBfa=mNeLt-4BFjEP4tqdDsnq+oMqqPr7fd9Wji2_9YXmQdA@mail.gmail.com M src/backend/replication/logical/slotsync.c
Guard against uninitialized default locale.
commit : 1d76927469d35f8dd6d90509618fda3e6bc3b7d6
author : Jeff Davis <jdavis@postgresql.org>
date : Mon, 8 Jun 2026 13:11:59 -0700
committer: Jeff Davis <jdavis@postgresql.org>
date : Mon, 8 Jun 2026 13:11:59 -0700 No known problem today, but defend against issues like dbf217c1c7 in
the future.
Discussion: https://postgr.es/m/d080287d8d2d14c246c86be2e9eb611fb6b27b11.camel@j-davis.com
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Backpatch-through: 17 M src/backend/utils/adt/pg_locale.c
Remove inappropriate translation marker in getObjectIdentityParts().
commit : c48c2bc37eabdd692cac9af5a57f8ef116b9c465
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 8 Jun 2026 15:23:48 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 8 Jun 2026 15:23:48 -0400 Strings built by this function are not supposed to be subject to
NLS translation, but commit 6566133c5 missed that memo, so that
object identities like "membership of role %s in role %s" were
translated. M src/backend/catalog/objectaddress.c
dict_synonym.c: remove incorrect outlen.
commit : 3805641cbc1e8fba1c6f82802ea1c4f7d1cae026
author : Jeff Davis <jdavis@postgresql.org>
date : Mon, 8 Jun 2026 11:47:40 -0700
committer: Jeff Davis <jdavis@postgresql.org>
date : Mon, 8 Jun 2026 11:47:40 -0700 Previously, outlen was miscalculated if case_sensitive was false and
str_tolower() changed the byte length of the string. If outlen was too
large, pnstrdup() would stop at the NUL terminator, preventing
overrun. But if outlen was too small, it would cause truncation.
Fix by just removing outlen. It was only used in a single site, which
could just as well use pstrdup().
Discussion: https://postgre.es/m/1101e1a3afbbabb503317069c40374b82e6f4cac.camel@j-davis.com
Reviewed-by: Tristan Partin <tristan@partin.io>
Backpatch-through: 14 M src/backend/tsearch/dict_synonym.c
Fix missed checks for hashability of container-type equality.
commit : 19152e3c29abc09a17f3c6252fe19f59449e827f
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 8 Jun 2026 11:48:07 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 8 Jun 2026 11:48:07 -0400 The operators for array_eq, record_eq, range_eq, and multirange_eq
are all marked oprcanhash, but there's a pitfall: their hash functions
can fail at runtime if the contained type(s) are not hashable.
Therefore, the planner has to check hashability of the contained types
before deciding it can use hashing in these cases. Not every place
had gotten this memo, and noplace at all had considered the issue
for ranges or multiranges. In particular we could attempt to use
hashing for a ScalarArrayOpExpr on a container type when it won't
actually work, leading to "could not identify a hash function ..."
runtime failures.
For the most part we should fix this in the lookup functions provided
by lsyscache.c, to wit get_op_hash_functions and op_hashjoinable.
But there's a problem: get_op_hash_functions is not passed the input
data type it would need to check. We mustn't change the API of that
exported function in a back-patched fix, and even if we wanted to,
its call sites in the executor mostly don't have easy access to the
required data type OID. Fortunately, the executor call sites don't
actually need fixing, because it's expected that the planner verified
hashability before building a plan that requires it. Therefore,
leave get_op_hash_functions as-is and invent a wrapper function
get_op_hash_functions_ext that does the additional checking needed
in the planner's uses.
We also need to fix hash_ok_operator (extending the fix in 647889667).
While at it, neaten up a couple of places in lookup_type_cache where
relevant code for multirange cases was written differently from the
code for other container types.
Note: while this touches pg_operator.dat, it's only to add oid_symbol
macros. So there's no on-disk data change and no need for a
catversion bump.
Reported-by: Andrei Lepikhov <lepihov@gmail.com>
Author: Andrei Lepikhov <lepihov@gmail.com>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/ed221f95-f09b-4a9c-b05b-e1fed621ec87@gmail.com
Backpatch-through: 14 M src/backend/optimizer/plan/subselect.c
M src/backend/optimizer/util/clauses.c
M src/backend/utils/cache/lsyscache.c
M src/backend/utils/cache/typcache.c
M src/include/catalog/pg_operator.dat
M src/include/utils/lsyscache.h
doc: Expand on proper use of refint.
commit : c0392783c541dac9e1148c5131882612fefaf9dc
author : Nathan Bossart <nathan@postgresql.org>
date : Mon, 8 Jun 2026 10:33:52 -0500
committer: Nathan Bossart <nathan@postgresql.org>
date : Mon, 8 Jun 2026 10:33:52 -0500 The security team has received a couple of reports about potential
SQL injection via refint's trigger arguments. We discussed this
while preparing CVE-2026-6637 and concluded that forcibly quoting
these arguments is more likely to break working code than to
prevent exploits. Unlike data values, the table/column names come
from trigger arguments, and there is little reason for a trigger
author to put hostile inputs into those arguments. So, let's
document it accordingly.
Reported-by: Nikolay Samokhvalov <nik@postgres.ai>
Reported-by: Alex Young <alex000young@gmail.com>
Reported-by: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Suggested-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Fujii Masao <masao.fujii@oss.nttdata.com>
Reviewed-by: Christoph Berg <myon@debian.org>
Reviewed-by: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Discussion: https://postgr.es/m/ahXP7z7nsfGPOZ3T%40nathan
Backpatch-through: 14 M doc/src/sgml/contrib-spi.sgml
ecpg: Reject multiple header items in GET/SET DESCRIPTOR
commit : fe8c0a762b30b94868b5d197cd63115b2f1f9faf
author : Fujii Masao <fujii@postgresql.org>
date : Mon, 8 Jun 2026 17:11:12 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Mon, 8 Jun 2026 17:11:12 +0900 Previously, ecpg accepted multiple descriptor header items in GET DESCRIPTOR
and SET DESCRIPTOR, but generated broken C code when they were used.
Although the grammar allowed this syntax, the implementation did not actually
support it.
This commit tightens the ecpg grammar so the header form of GET/SET DESCRIPTOR
accepts only a single header item, matching the implementation and preventing
generation of broken C code.
Also update the documentation synopsis accordingly.
Backpatch to all supported versions.
Author: Masashi Kamura <kamura.masashi@fujitsu.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Lakshmi G <lakshmigcdac@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/OS9PR01MB13174AD7D1829D0644B6BB90E9447A@OS9PR01MB13174.jpnprd01.prod.outlook.com
Backpatch-through: 14 M doc/src/sgml/ecpg.sgml
M src/interfaces/ecpg/preproc/ecpg.trailer
Fix memory leak in pgstat_progress_parallel_incr_param()
commit : 8ad4148313d42a6d260c5c63f295bf3a22dae252
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 8 Jun 2026 15:29:21 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Mon, 8 Jun 2026 15:29:21 +0900 When called from a parallel worker, this function calls initStringInfo()
and pq_beginmessage(), causing a StringInfo allocation to happen twice.
pq_endmessage() frees only the second allocation, with each call leaking
~1 kB into the per-worker memory context. This could cause a few
hundred megabytes worth of memory to pile up until the worker exits (the
message allocations happen in the parallel worker context), with the
situation being worse the longer a parallel worker runs.
Oversight in f1889729dd3.
Author: Baji Shaik <baji.pgdev@gmail.com>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Reviewed-by: Tristan Partin <tristan@partin.io>
Discussion: https://postgr.es/m/CA+fm-RMopta1Dmq8udiU5sp+zwTvhUf4+xfbr3rZDfczH+p-xw@mail.gmail.com
Backpatch-through: 17 M src/backend/utils/activity/backend_progress.c
psql: Fix expanded aligned output
commit : efd885d05b8beded386fbb5a9d737dc9e65289a9
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 8 Jun 2026 14:37:57 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Mon, 8 Jun 2026 14:37:57 +0900 When a table's columns are narrower than the record header line, the
expanded aligned format produced misaligned output because the data
column width was not adjusted to match the record header width, leading
to output like:
+-[ RECORD 1 ]-+
| a | 10 |
| b | 20 |
+---+----+
This commit adjusts the output so as the column width match with the
header line, giving:
+-[ RECORD 1 ]-+
| a | 10 |
| b | 20 |
+---+----------+
Author: Pavel Stehule <pavel.stehule@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAFj8pRCzGpsr9zTHbtTd4mGh2YPJqOEgLgt8JLiopuYA9_1xGw@mail.gmail.com
Backpatch-through: 14 M src/fe_utils/print.c
M src/test/regress/expected/psql.out
M src/test/regress/sql/psql.sql
Lift shutdown assertion in pgstats for WAL senders
commit : 4801610f7c66661f2b8722a2c5561273e210960b
author : Michael Paquier <michael@paquier.xyz>
date : Sat, 6 Jun 2026 08:52:19 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Sat, 6 Jun 2026 08:52:19 +0900 Before v17, WAL senders can shut down after the checkpointer. If a WAL
sender still has pending statistics when the checkpointer has already
exited, its shutdown callback may attempt to report those statistics and
trigger assertions in pgstats. In that case, the pending statistics are
lost.
This commit adjusts the assertion handling so that attempts to report
pending WAL sender statistics after the checkpointer has completed its
final stats flush are skipped.
Preserving the existing assertion would require backpatching an
equivalent of 87a6690cc69, ensuring that the checkpointer is always the
last process to exit. Such a change would be considerably more invasive
and risky for stable branches because it alters the shutdown sequence,
and the consequence is only some loss of stats data for the WAL sender.
This assertion failure was periodically detected in the buildfarm,
leading to spurious failures.
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/18158-88f667028dbc7e7b@postgresql.org
Backpatch-through: 15-17 M src/backend/utils/activity/pgstat.c
pg_surgery: Fix off-by-one bug with heap offset
commit : 0bcf19c9e8fc553b2a9bd731d90020fe22def18f
author : Michael Paquier <michael@paquier.xyz>
date : Sat, 6 Jun 2026 08:16:41 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Sat, 6 Jun 2026 08:16:41 +0900 heap_force_common() declared a boolean array indexed with an
OffsetNumber for a size of MaxHeapTuplesPerPage. OffsetNumbers are
1-based, so an input TID whose offset number equals MaxHeapTuplesPerPage
wrote one byte past the end of the stack array, crashing the server.
Like heapam_handler.c, this commit changes the array so as it uses a
0-based index, substracting one from the OffsetNumbers.
Reported-by: Wang Yuelin <violin0613@tju.edu.cn>
Reviewed-by: Ashutosh Sharma <ashu.coek88@gmail.com>
Discussion: https://postgr.es/m/20260604002256.40f1fd544@smtp.qiye.163.com
Backpatch-through: 14 M contrib/pg_surgery/heap_surgery.c
refint: Remove plan cache.
commit : 66a5146dc73d3ac1befe6ab595815157d5281cb5
author : Nathan Bossart <nathan@postgresql.org>
date : Fri, 5 Jun 2026 12:08:05 -0500
committer: Nathan Bossart <nathan@postgresql.org>
date : Fri, 5 Jun 2026 12:08:05 -0500 Presently, refint stores plans in a per-backend cache to avoid
re-preparing in each call. This has a few problems. For one,
check_foreign_key() embeds the new key values in its cascade-UPDATE
queries, so a cached plan reuses the values from preparation.
Also, the cache is never invalidated, so it can return stale
entries that cause other problems. There may very well be more
bugs lurking.
We could spend a lot of time trying to address all these problems,
but this module is primarily intended as sample code, and by all
indications, it sees minimal use. Furthermore, there is a growing
consensus for removing refint in v20. However, since we'll need to
support it on the back-branches for a while longer, it probably
still makes sense to fix some of the more egregious bugs.
Therefore, let's just remove refint's plan cache entirely. That
means we'll re-prepare on every call, but that seems quite unlikely
to bother anyone. On v17 and older versions, the regression test
for triggers fails after this change, so I've borrowed pieces of
commit 8cfbdf8f4d to fix it.
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/CAJTYsWXU%2BfhuzrEd_bnrxyGH3%2Bny8QRQC2QHf3ws6s9iki3c2Q%40mail.gmail.com
Backpatch-through: 14 M contrib/spi/refint.c
M src/test/regress/expected/triggers.out
M src/test/regress/sql/triggers.sql
Fix off-by-one with NFC recomposition for Hangul U+11A7 (TBASE)
commit : 0c9cbbfb5be79d2061d7f897f6c6f4bccb886062
author : Michael Paquier <michael@paquier.xyz>
date : Fri, 5 Jun 2026 07:50:13 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Fri, 5 Jun 2026 07:50:13 +0900 The NFC recomposition incorrectly included TBASE as a valid T syllable,
which is incorrect based on the Unicode specification (TBASE is one
below the start of the range, range beginning at U+11A8).
This would cause the TBASE to be silently swallowed in the
normalization, leading to an incorrect result.
A couple of regression tests are added to check more patterns with
Hangul recomposition and decomposition, on top of a test to check the
problem with TBASE. Diego has submitted the code fix, and I have
written the tests.
Author: Diego Frias <mail@dzfrias.dev>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/B92ED640-7D4A-4505-B09F-3548F58CBB16@dzfrias.dev
Backpatch-through: 14 M src/common/unicode_norm.c
M src/test/regress/expected/unicode.out
M src/test/regress/sql/unicode.sql
Improve reporting of invalid weight symbols in setweight() et al.
commit : 0626fbfebae51a048b5415710200554eac65ff5e
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Thu, 4 Jun 2026 12:24:51 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Thu, 4 Jun 2026 12:24:51 -0400 This commit addresses two related issues:
tsvector_filter() assumed it could print an incorrect weight value
with %c. This could result in an invalidly-encoded error message
if the database encoding is multibyte and the char value has its
high bit set. Weight values that are ASCII control characters
could render illegibly too. Fix by printing such values in octal
(\ooo), similarly to how charout() would render them.
tsvector_setweight() and tsvector_setweight_by_filter() reported
the same unrecognized-weight error condition with elog(), as though
it were an internal error. That'd not translate, would produce an
unwanted XX000 SQLSTATE code, and also reported the bad value as a
decimal integer which seems unhelpful. Fix by refactoring so that
all three functions share one copy of the code that interprets a
weight argument.
The invalid-encoding aspect seems to me (tgl) to justify
back-patching.
Author: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAON2xHNaeLAUzRCXL5AmXLcXaSE_gWAVjWQRmLzc_oZ=1_Vf4Q@mail.gmail.com
Backpatch-through: 14 M src/backend/utils/adt/tsvector_op.c
Fix another case of indirectly casting away const.
commit : cefe7576404f5c96f25d4f683ffab72634c421fa
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Thu, 4 Jun 2026 11:37:43 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Thu, 4 Jun 2026 11:37:43 -0400 Like 8f1791c61, this fixes a case of implicitly casting away
const by not treating the result of strrchr() on a const pointer
as const. This was missed at the time because the machines
reporting those warnings weren't building with --with-llvm.
While here, clean up another infelicity: in the probably-
impossible case that the input string contains only one dot,
this function would call pnstrdup() with a length of -1
and thereby emit a module name equal to the function name.
It seems to me we should emit modname = NULL instead.
Also remove a useless Assert and two redundant assignments.
Back-patch, as 8f1791c61 was, so that users of back branches
don't see this warning when building with late-model gcc.
Reported-by: hubert depesz lubaczewski <depesz@depesz.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/aiGNJ89PBqvq2Yyz@depesz.com
Backpatch-through: 14 M src/backend/jit/llvm/llvmjit.c
Fix race in ReplicationSlotRelease() for ephemeral slots
commit : 080d61f07ce2852aff32b05aba5c417bad8859d2
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 3 Jun 2026 18:47:10 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 3 Jun 2026 18:47:10 +0900 When releasing an ephemeral replication slot, ReplicationSlotRelease()
drops the slot via ReplicationSlotDropAcquired().
However, after dropping the slot, ReplicationSlotRelease() continued
to use its local "slot" pointer, which still referenced the dropped
slot's former shared-memory entry. It could then update fields such as
effective_xmin in that entry.
Once an ephemeral slot has been dropped (via ReplicationSlotDropAcquired()),
its slot array entry can be reused immediately by another backend
creating a new slot. As a result, those updates could corrupt
the state of an unrelated replication slot.
Fix by skipping those shared-memory updates for phemeral slots and
performing them only for non-ephemeral slots, whose shared-memory
entries remain valid after release.
Backpatch to all supported versions.
Author: Zhijie Hou <houzj.fnst@fujitsu.com>
Reviewed-by: Masao Fujii <masao.fujii@gmail.com>
Reviewed-by: Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/TY4PR01MB177184FF9EE916F577E1F554194082@TY4PR01MB17718.jpnprd01.prod.outlook.com
Backpatch-through: 14 M src/backend/replication/slot.c
Fix copy-paste error in hash_record_extended()
commit : 203e238bbe8a2b5357157ae2e4b0c7f7a6b5b94d
author : Michael Paquier <michael@paquier.xyz>
date : Wed, 3 Jun 2026 12:47:28 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Wed, 3 Jun 2026 12:47:28 +0900 The code failed to initialize the second isnull argument passed to
FunctionCallInvoke(). This is harmless for existing in-core extended
hash support functions, since FunctionCallInvoke() does not use the
value (note that all the in-core extended hash functions are strict),
examining only the argument values. However, extension-provided
extended hash functions could be affected if they inspect
PG_ARGISNULL(1).
Oversight in 01e658fa74cb.
Author: Man Zeng <zengman@halodbtech.com>
Discussion: https://postgr.es/m/tencent_7818173C01E01836109848C3@qq.com
Backpatch-through: 14 M src/backend/utils/adt/rowtypes.c
Fix wrong unsafe-flag test in check_output_expressions()
commit : c3f1db2b88225950a25dc76bc2dfc10632be6eee
author : Richard Guo <rguo@postgresql.org>
date : Wed, 3 Jun 2026 09:36:52 +0900
committer: Richard Guo <rguo@postgresql.org>
date : Wed, 3 Jun 2026 09:36:52 +0900 The check for window functions (point 4) guarded on the wrong bit: it
tested UNSAFE_NOTIN_DISTINCTON_CLAUSE while setting
UNSAFE_NOTIN_PARTITIONBY_CLAUSE. Each check in this loop guards on
the same bit it is about to set, as an idempotency optimization, since
unsafeFlags[] is accumulated across the arms of a set operation and
there is no point recomputing a column's status once its bit is
present.
This is not a live bug. When UNSAFE_NOTIN_PARTITIONBY_CLAUSE is
already set but UNSAFE_NOTIN_DISTINCTON_CLAUSE is not, the guard fails
to skip targetIsInAllPartitionLists() and recomputes it, but setting
the same bit again changes nothing. When
UNSAFE_NOTIN_DISTINCTON_CLAUSE is already set, point 4 is skipped and
UNSAFE_NOTIN_PARTITIONBY_CLAUSE is left unset; but such a column is
already unsafe for pushdown via UNSAFE_NOTIN_DISTINCTON_CLAUSE, so the
outcome is unchanged.
To fix, test UNSAFE_NOTIN_PARTITIONBY_CLAUSE, matching the bit being
set and the pattern of the surrounding checks.
Back-patch to v15, where the buggy check was introduced.
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49Q_xnF_P2QSUyDzJ34MnrO7dh-cUAaK2HJPgSgh88NcA@mail.gmail.com
Backpatch-through: 15 M src/backend/optimizer/path/allpaths.c
Use term "referenced" rather than "dependent" in dependency locking
commit : 60300c191634cf6036d52386f17399a493874588
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 28 May 2026 21:27:50 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Thu, 28 May 2026 21:27:50 +0300 Reported-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://www.postgresql.org/message-id/20260528.114608.488039299811669368.horikyota.ntt@gmail.com
Backpatch-through: 14 M src/backend/catalog/pg_depend.c
M src/test/isolation/expected/ddl-dependency-locking.out
Make stack depth check work with asan's use-after-return
commit : 7ab11e09f98b6f144aabc3c36b86738ecc83049e
author : Andres Freund <andres@anarazel.de>
date : Thu, 28 May 2026 11:34:12 -0400
committer: Andres Freund <andres@anarazel.de>
date : Thu, 28 May 2026 11:34:12 -0400 With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.
We started using __builtin_frame_address() with de447bb8e6fb, however as of
that commit we just used it for the stack base address, not for the value to
compare to the base address. Now we use it for both.
When building without __builtin_frame_address() support, we continue to use
stack variables for the stack depth determination.
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/2kk4z4odvuyrg7qlwjd7ft4eron4cle4btb33v4qatgsdkayir@gj6e62rgsel4
Backpatch-through: 14 M .cirrus.tasks.yml
M src/backend/tcop/postgres.c
Fix race between ProcSignalInit() and EmitProcSignalBarrier().
commit : a651b8a89e7f76696ddc89a565b39039568840bc
author : Masahiko Sawada <msawada@postgresql.org>
date : Wed, 27 May 2026 16:26:02 -0700
committer: Masahiko Sawada <msawada@postgresql.org>
date : Wed, 27 May 2026 16:26:02 -0700 Previously, ProcSignalInit() read the global barrier generation before
publishing its PID into pss_pid. This created a race condition: a
process could initialize its local generation with an older global
value, while a concurrent EmitProcSignalBarrier() might skip that
process because its pss_pid was still zero. This resulted in
WaitForProcSignalBarrier() hanging indefinitely.
Fix this by publishing pss_pid before reading psh_barrierGeneration
with a memory barrier so that the store to pss_pid is ordered before
the load. A concurrent EmitProcSignalBarrier() then either observes
the published PID and signals this slot, or completes its generation
increment before we load it.
While this race has become more visible due to recent features using
signal barriers in more places (such as online wal_level changes), the
issue is theoretically present since signal barriers were introduced
to release smgr caches (e.g., in DROP DATABASE). v14 has the
procsiangl barrier infrastricutre but no in-tree caller that actually
emits a barrier, so the case is unreachable there.
This issue was also reported by buildfarm member flaviventris.
Reported-by: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Alexander Lakhin <exclusion@gmail.com>
Reviewed-by: Matthias van de Meent <boekewurm+postgres@gmail.com>
Discussion: https://postgr.es/m/CAEze2WgAJmWReDN7Chtba8Er2YBvKCoa0KVN25-1evnTrHsLyA@mail.gmail.com
Backpatch-through: 15 M src/backend/storage/ipc/procsignal.c
Avoid orphaned objects dependencies
commit : 3a9909eda20775658903889b6150b756e5a8a57d
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Wed, 27 May 2026 18:35:58 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Wed, 27 May 2026 18:35:58 +0300 Concurrent DDL can leave behind objects referencing other objects that
no longer exist. This can happen if an object is dropped, while a new
object that depends on it is created concurrently. For example:
session 1: BEGIN; CREATE FUNCTION myschema.myfunc() ...;
session 2: DROP SCHEMA myschema;
session 1: COMMIT;
DROP SCHEMA does check that there are no objects dependending on the
schema being dropped, but it does not see objects being concurrently
created by other sessions. Even if it did, this scenario would still
fail:
session 1: BEGIN: DROP SCHEMA myschema;
session 2: CREATE FUNCTION myschema.myfunc() ...;
session 1: COMMIT;
When the DROP SCHEMA runs, the schema was empty, but the new function
is created in it before the dropping transaction completes. The CREATE
FUNCTION does not see that the schema is concurrently being dropped.
In both of these scenarios, the function is left behind in the schema
that no longer exists.
To fix, acquire AccessShareLock on all referenced objects when
recording dependencies. This conflicts with the AccessExclusiveLock
taken by DROP, preventing the race. After acquiring the lock, verify
that the object still exists, and if it was dropped concurrently,
report an error. We already had such a mechanism for shared
dependencies, but for some reason we didn't do it for in-database
dependendies.
Ideally the locks would be acquired much earlier when creating a new
object, but that will require modifying a lot of callers. This check
while recording the dependency is a nice wholesale protection, and
even if we change all the CREATE commands to acquire locks earlier,
it's still good to have this as a backstop to catch any cases where we
forgot to do so.
The patch adds a few tests for some cases that left behind orphaned
objects before this. It also adds a test for roles, which already had
such protection, although that test is partially disabled because the
error message includes an OID which is not predictable.
Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Discussion: https://postgr.es/m/ZiYjn0eVc7pxVY45@ip-10-97-1-34.eu-west-3.compute.internal
Backpatch-through: 14 M src/backend/catalog/pg_depend.c
A src/test/isolation/expected/ddl-dependency-locking.out
M src/test/isolation/isolation_schedule
A src/test/isolation/specs/ddl-dependency-locking.spec
M src/test/regress/expected/alter_table.out
Don't try to record dependency on a dropped column's datatype
commit : c1588f92a915f4af890c70c66891a40ee23588b4
author : Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Wed, 27 May 2026 18:35:55 +0300
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>
date : Wed, 27 May 2026 18:35:55 +0300 When creating a relation with a dropped column, we called
recordDependencyOn() also on the datatype of the dropped column, which
is always InvalidOid. In versions 15 and above, that was harmless
because recordDependencyOn() considers InvalidOid as a pinned object,
and skips over it. On version 14, isPinnedObject() does not consider
InvalidOid as pinned, so we created a bogus pg_depend entry with
refobjectid == 0.
As far as I can tell, the only case when AddNewAttributeTuples() is
called with dropped columns is when performing a table-rewriting ALTER
TABLE command. That temporarily creates a new relation with the same
columns, including dropped ones, then swaps the relations, and drops
the newly created table again. So even on version 14, the bogus
pg_depend entry was only on the transient relation that was dropped at
the end of the ALTER TABLE command, which was harmless.
Even though this is harmless, let's be tidy, similar to commit
713bce9484. The reason I noticed this now and why I backported this,
is because the next commit will add code to acquire locks on the
referenced objects, and we don't want to acquire a lock on InvalidOid.
Discussion: https://postgr.es/m/ZiYjn0eVc7pxVY45@ip-10-97-1-34.eu-west-3.compute.internal
Backpatch-through: 14 M src/backend/catalog/heap.c
Fix procLatch ownership race in ProcKill()
commit : e14b4ea4a6ece9d89a9cb5cf40472664f26f322f
author : Michael Paquier <michael@paquier.xyz>
date : Wed, 27 May 2026 17:19:55 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Wed, 27 May 2026 17:19:55 +0900 DisownLatch() was executed after the PGPROC entry of the process
terminated is pushed back into a freelist. A newly-forked backend that
recycles the slot could call OwnLatch() and PANIC with a "latch already
owned by PID", taking down the server.
There were two scenarios related to lock groups where this issue could
be reached:
* A follower pushes the leader's PGPROC back to the freelist while the
leader has not yet called DisownLatch() in its own ProcKill().
* A leader outliving all its followers pushes its own PGPROC onto the
freelist before reaching DisownLatch(), which would be the most common
scenario.
This issue is fixed by calling SwitchBackToLocalLatch() and
DisownLatch() at an earlier phase of ProcKill(), before any freelist
manipulation happens, so that the slot of the backend terminated is
never exposed as owning a latch.
Note that pgstat_reset_wait_event_storage() is kept at a later stage.
An upcoming commit will take advantage of that by introducing a test
able to check the original PANIC scenario.
Author: Vlad Lesin <vladlesin@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/d2983796-2603-41b7-a66e-fc8489ddb954@gmail.com
Backpatch-through: 14 M src/backend/storage/lmgr/proc.c
Fix race conditions in ProcKill()'s lock-group freelist handling
commit : d489c4439e5ba48b6621f34afe75f994f4682cb0
author : Michael Paquier <michael@paquier.xyz>
date : Wed, 27 May 2026 14:49:01 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Wed, 27 May 2026 14:49:01 +0900 This commit fixes two bugs in ProcKill()'s lock-group teardown freelist
publication:
* a double push of the leader's PGPROC that corrupts the freelist.
* a leak of the last follower's PGPROC slot.
ProcKill()'s lock-group teardown had two PGPROC freelist updates
scattered through the function, done under two separate freeProcsLock
acquisitions:
* A follower's push of the leader's PGPROC, done when a follower is the
last group member exiting.
* Every backend's self-push at the bottom of the function.
The two freelist updates were coordinated only by inspecting
proc->lockGroupLeader, which a follower could clear as a side effect of
pushing the leader. This coordination was broken. For example, with
two concurrent backends:
* The follower clears leader->lockGroupLeader and pushes the leader's
PGPROC under leader_lwlock.
* The follower does not clear its own proc->lockGroupLeader, being
skipped.
* When the leader reaches the bottom of ProcKill(), it sees a NULL
proc->lockGroupLeader (the follower cleared it) and pushes itself,
causing a second dlist_push_tail() of the same node onto the same
freelist.
* The follower at the bottom sees its own proc->lockGroupLeader being
not NULL (never cleared) and skips its own push, causing its own slot
to leak.
This commit refactors the freelist manipulation to be done in two
distinct phases, each step using its own lock acquisition to ensure that
each freelist operation happens in an isolated manner for each backend
(follower or leader):
- First, under a single leader_lwlock acquisition, check the state of
the lock-group. Depending on if we are dealing with a follower and/or a
leader, and if the leader has exited before a follower, then set some
state booleans that define which actions should be taken with the
freelist.
- Second, under a single freeProcsLock acquisition, perform the cleanup
actions, self-push of a backend and/or push of the leader back to the
freelist.
This is an old issue, dating back to 9.6 where parallel workers and lock
grouping has been added.
Author: Vlad Lesin <vladlesin@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/d2983796-2603-41b7-a66e-fc8489ddb954@gmail.com
Backpatch-through: 14 M src/backend/storage/lmgr/proc.c
pg_createsubscriber: Fix cleanup of publisher-side objects after errors
commit : c03784a2181594d150c7f486308172dee19c5321
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 27 May 2026 10:35:49 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 27 May 2026 10:35:49 +0900 When pg_createsubscriber fails after creating logical replication
objects, it should remove the publication and replication slot that
it created on the publisher.
Previously, if dropping subscriber-side objects failed,
pg_createsubscriber reset its internal cleanup state too early. As a
result, the exit-time cleanup could skip removing the publication or
replication slot on the publisher.
This could leave pg_createsubscriber-created objects behind on
the publisher after a failed run. That can make a retry harder,
because the leftover publication or replication slot may need to be
removed manually before running pg_createsubscriber again.
In the case of a replication slot, leaving it behind can also retain
WAL files longer than expected.
The cause of this issue was that the flags made_publication and
made_replslot tracking whether pg_createsubscriber created
a publication or replication slot on the primary were incorrectly
reset to false when failures occurred while dropping objects
on the subscriber.
This commit fixes the issue by preventing those cleanup flags from
being reset even when failures occurred while dropping objects
on the subscriber, ensuring proper cleanup of primary objects
before exit on failure.
Backpatch to v17, where pg_createsubscriber was added.
Author: Nisha Moond <nisha.moond412@gmail.com>
Reviewed-by: David G. Johnston <david.g.johnston@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Peter Smith <smithpb2250@gmail.com>
Discussion: https://postgr.es/m/CABdArM5V9QKK1PkLY9dpgAcZa3kUp84-wPqPovxvdLOri4=69w@mail.gmail.com
Backpatch-through: 17 M src/bin/pg_basebackup/pg_createsubscriber.c
Skip pg_database.dathasloginevt cleanup on standby
commit : 4a375527a19545dff0321349c42659e5f097d94b
author : Alexander Korotkov <akorotkov@postgresql.org>
date : Wed, 27 May 2026 02:26:50 +0300
committer: Alexander Korotkov <akorotkov@postgresql.org>
date : Wed, 27 May 2026 02:26:50 +0300 EventTriggerOnLogin() tries to clear pg_database.dathasloginevt when
the database no longer has any login event triggers but the flag is
still set. To make that safe against concurrent flag setters, it
takes a conditional AccessExclusiveLock on the database object.
On a hot standby, that lock acquisition fails outright with
FATAL: cannot acquire lock mode AccessExclusiveLock on database
objects while recovery is in progress
because LockAcquireExtended() refuses locks stronger than
RowExclusiveLock on database objects during recovery. The standby
already replays the flag's value from the primary, so the dangling
flag is the result of replaying a state in which the primary had
already dropped its login event triggers but not yet run a login
event trigger pass to clear the flag. Any session connecting to the
standby in that window therefore fails to connect.
Skip the cleanup on a standby. The flag will be cleared via WAL
replay once the primary clears it on its side.
Add a recovery TAP test that reproduces the original report: create
and drop a login event trigger on the primary in one session, wait
for the standby to replay, then verify that a fresh connection to
the standby succeeds.
Backpatch to v17, where the login event triggers were introduced.
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reported-by: Egor Chindyaskin <kyzevan23@mail.ru>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/19488-d7ccfca2bf6b74b0%40postgresql.org
Backpatch-through: 17 M src/backend/commands/event_trigger.c
M src/test/recovery/meson.build
A src/test/recovery/t/053_standby_login_event_trigger.pl
Fix missed ReleaseVariableStats() in intarray's _int_matchsel().
commit : 94b57ab54a0ed4b4fcc8ee0bb5860461b926bbb7
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 25 May 2026 18:15:49 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Mon, 25 May 2026 18:15:49 -0400 Given a WHERE clause like "int[] @@ query_int" or "query_int ~~ int[]"
where the query_int side is a table column having statistics,
_int_matchsel() exited without remembering to free the statistics
tuple. This would typically lead to warnings about cache refcount
leakage, like
WARNING: resource was not closed: cache pg_statistic (73), tuple 42/12 has count 1
It's been wrong since this code was added, in commit c6fbe6d6f.
Bug: #19492
Reported-by: Man Zeng <zengman@halodbtech.com>
Author: Man Zeng <zengman@halodbtech.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19492-ddcd0e22399ef85a@postgresql.org
Backpatch-through: 14 M contrib/intarray/_int_selfuncs.c
Fix size check in statext_dependencies_deserialize()
commit : e4af8009ba94812aff8e3e465a51f9e7aee68350
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 25 May 2026 14:39:02 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Mon, 25 May 2026 14:39:02 +0900 The check for the minimum expected bytea size of a MVDependencies object
was using SizeOfItem() for its calculation. This macro uses the number
of attributes in a single dependency.
This minimum size calculation should be based on MinSizeOfItems(), that
computes the minimum expected size as the header plus the
minimally-sized number of dependency items.
Oversight in d08c44f7a4ec.
Author: Ilia Evdokimov <ilya.evdokimov@tantorlabs.com>
Discussion: https://postgr.es/m/4b8d299d-2505-4c30-bf80-0f697410db35@tantorlabs.com
Backpatch-through: 14 M src/backend/statistics/dependencies.c
Avoid exposing WAL receiver raw conninfo during timeline jumps
commit : c89499a79898c20907308a009000a8967c8c272c
author : Michael Paquier <michael@paquier.xyz>
date : Sat, 23 May 2026 08:10:14 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Sat, 23 May 2026 08:10:14 +0900 When reusing an existing WAL receiver after it has reached
WALRCV_WAITING for new instructions, RequestXLogStreaming() copied
PrimaryConnInfo into WalRcv->conninfo before switching the state to
WALRCV_RESTARTING. At that point ready_to_display could still be true,
so pg_stat_wal_receiver could expose the raw connection string,
including sensitive fields, but it should only show the user-displayable
version of the connection string.
WALRCV_RESTARTING does not establish a new connection. The waiting WAL
receiver reuses its existing connection and only needs a new startpoint
and timeline, so there is no need to copy the raw connection string into
shared memory again. Let's only copy conninfo when launching a new WAL
receiver after WALRCV_STOPPED, not while waiting for instructions.
This commit adds coverage for the case fixed by this commit to the
timeline-switch test by verifying that the WAL receiver conninfo remains
consistent across the jump.
Backpatch all the way down, as this issue is possible since
pg_stat_wal_receiver has been introduced.
Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/EF91FF76-1E2B-4F3B-9162-290B4DC517FF@gmail.com
Backpatch-through: 14 M src/backend/replication/walreceiverfuncs.c
M src/test/recovery/t/004_timeline_switch.pl
pg_recvlogical: Honor source cluster file permissions for output files
commit : ddd12d1a5c4d980c5f31dc7d096012547b724e55
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 20 May 2026 15:54:13 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 20 May 2026 15:54:13 +0900 Commit c37b3d08ca6 attempted to preserve group permissions on pg_recvlogical
output files when group access was enabled on the source cluster. However,
the output files were still created with a fixed S_IRUSR | S_IWUSR mode,
preventing group-read permissions from being applied.
This commit fixes the issue by creating output files with pg_file_create_mode
instead of a hard-coded mode. This allows pg_recvlogical to correctly preserve
group permissions from the source cluster.
Backpatch to all supported branches.
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwHhpizYzMo3nFP4GkNMueSNMY3QfC-gBN1VTXtuiANDvw@mail.gmail.com
Backpatch-through: 14 M doc/src/sgml/ref/pg_recvlogical.sgml
M src/bin/pg_basebackup/pg_recvlogical.c
injection_points: Move some structs to new header injection_points.h
commit : 01a479745488533aaa2c23d021c1f535a910ed07
author : Michael Paquier <michael@paquier.xyz>
date : Mon, 18 May 2026 11:11:46 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Mon, 18 May 2026 11:11:46 +0900 This commit moves the definitions of InjectionPointConditionType and
InjectionPointCondition into a new header local to the test module
injection_points.h, so as these can be shared across more files in the
module. A patch for a bug fix is under discussion, whose proposed test
will benefit from this refactoring.
Backpatch down to where the module exists, as this should be useful for
future bug fixes, even cases unrelated to the thread where this change
has been discussed.
Author: Andrey Borodin <x4mmm@yandex-team.ru>
Author: Vlad Lesin <vladlesin@gmail.com>
Discussion: https://postgr.es/m/d2983796-2603-41b7-a66e-fc8489ddb954@gmail.com
Backpatch-through: 17 M src/test/modules/injection_points/injection_points.c
A src/test/modules/injection_points/injection_points.h
Use ereport(ERROR), not Assert(), for publisher tuples missing columns.
commit : 15f4e3d0ce92474220fcc83f789c45051c77da0f
author : Noah Misch <noah@leadboat.com>
date : Sat, 16 May 2026 18:01:35 -0700
committer: Noah Misch <noah@leadboat.com>
date : Sat, 16 May 2026 18:01:35 -0700 Three locations use Assert() to guard against a mismatch between the
number of columns advertised in the RELATION message and the number
actually received in the subsequent INSERT/UPDATE tuple message. Since
these values originate from the publisher, the check must survive into
production builds.
A malicious or buggy publisher can send a RELATION claiming N columns
and an INSERT claiming M < N columns. The subscriber's apply worker
indexes into colvalues[]/colstatus[] using column indices from the
RELATION message's attribute map, causing a heap out-of-bounds read when
the tuple's column array is smaller than expected. We've looked, without
success, for a scenario in which the publisher holds sufficient control
over these out-of-bounds bytes to exploit this or even to reach a
SIGSEGV. Despite not finding one, the code has been fragile. Back-patch
to v14 (all supported versions).
Reported-by: Varik Matevosyan <varikmatevosyan@gmail.com>
Author: Varik Matevosyan <varikmatevosyan@gmail.com>
Discussion: https://postgr.es/m/CA+bBoog3cCogktzfLb9bppUByu-10B3CFp8u=iKXG_OvtAguCw@mail.gmail.com
Backpatch-through: 14 M src/backend/replication/logical/worker.c
Doc: fix release-note typo.
commit : ab931303561da5244ba21f0f8fbe4a9ec837160d
author : Tom Lane <tgl@sss.pgh.pa.us>
date : Fri, 15 May 2026 18:32:33 -0400
committer: Tom Lane <tgl@sss.pgh.pa.us>
date : Fri, 15 May 2026 18:32:33 -0400 This mention of memcpy() should of course have said memcmp().
Reported-by: chris@chrullrich.net
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/177883653690.764749.14038057906859461991@wrigleys.postgresql.org
Backpatch-through: 14 M doc/src/sgml/release-17.sgml
Re-add regression tests for ltree and intarray
commit : a6c430cabedca37eb0530a02d8d8f19e46aeec73
author : Michael Paquier <michael@paquier.xyz>
date : Fri, 15 May 2026 18:02:49 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Fri, 15 May 2026 18:02:49 +0900 These tests have been removed by 906ea101d0d5, due to some of them being
unstable in the buildfarm with low max_stack_depth values. They are now
reworked so as they should be more portable.
The tests to cover the findoprnd() overflows use a balanced tree to
avoid using too much stack, per a suggestion and an investigation by Tom
Lane.
Note: This is initially applied only on HEAD; a backpatch will follow
should the buildfarm be fine with the situation.
Discussion: https://postgr.es/m/agZc6XecyE7E7fep@paquier.xyz
Backpatch-through: 14 M contrib/intarray/expected/_int.out
M contrib/intarray/sql/_int.sql
M contrib/ltree/expected/ltree.out
M contrib/ltree/sql/ltree.sql
refint: Fix segfault in check_foreign_key().
commit : 6b4de201e82f938b159033bb9d664e91107bf051
author : Nathan Bossart <nathan@postgresql.org>
date : Thu, 14 May 2026 13:11:49 -0500
committer: Nathan Bossart <nathan@postgresql.org>
date : Thu, 14 May 2026 13:11:49 -0500 When an UPDATE statement triggers check_foreign_key() with the
action set to "cascade", it generates more UPDATE statements to
modify the key values in referencing relations. If a new key value
is NULL, SPI_getvalue() returns a NULL pointer, which is
subsequently passed to quote_literal_cstr(), causing a segfault.
To fix, skip quoting when a new key value is NULL and insert an
unquoted NULL keyword instead.
Oversight in commit 260e97733b. While the refint documentation
recommends marking primary key columns NOT NULL, the aforementioned
scenario accidentally worked on platforms where snprintf()
substitutes "(null)" for NULL pointers. Note that for
character-type columns, the old code quoted "(null)" as a string
literal, so this didn't always produce correct results. But it
still seems better to fix this than to reject cases that previously
worked.
Reported-by: Nikita Kalinin <n.kalinin@postgrespro.ru>
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Pierre Forstmann <pierre.forstmann@gmail.com>
Discussion: https://postgr.es/m/19476-bd04ea6241345303%40postgresql.org
Backpatch-through: 14 M contrib/spi/refint.c
Prevent access to other sessions' temp tables
commit : 4dfae59a1d31651adec524cbeb386c6c3e5f8cba
author : Alexander Korotkov <akorotkov@postgresql.org>
date : Thu, 14 May 2026 12:25:19 +0300
committer: Alexander Korotkov <akorotkov@postgresql.org>
date : Thu, 14 May 2026 12:25:19 +0300 Commit b7b0f3f2724 ("Use streaming I/O in sequential scans") routed
sequential scans through read_stream_next_buffer(), bypassing the
RELATION_IS_OTHER_TEMP() check in ReadBufferExtended(). As a result,
a superuser can attempt to read or modify temp tables of other
sessions through the read-stream path. When the query plan uses no index,
SELECT/UPDATE/DELETE/MERGE silently see no rows / report zero affected rows,
and COPY produces an empty output -- because the buffer manager has no
visibility into the owning session's local buffers and silently returns
nothing. Any query plan that uses, for instance, a btree index
still errors out via the existing check in ReadBufferExtended(), which
is reached from hio.c and nbtree respectively, but this is incidental.
Fix by enforcing RELATION_IS_OTHER_TEMP() at the three additional
buffer-manager entry points:
- read_stream_begin_impl() rejects the read at stream setup time,
covering sequential and bitmap scans that go through the
read-stream path.
- ReadBuffer_common() becomes the canonical place for the check,
consolidating the existing one previously kept in
ReadBufferExtended(). All ReadBufferExtended() callers go through
ReadBuffer_common(), so the consolidation is behavior-preserving.
- StartReadBuffersImpl() catches direct callers of StartReadBuffers()
that bypass both of the above. This is currently defense-in-depth,
but documents the contract for future code.
The companion test in src/test/modules/test_misc was added in the
preceding commit; this commit updates the assertions for SELECT,
UPDATE, DELETE, MERGE, and COPY (which previously documented the
bug as silent success) to expect the new error.
Author: Jim Jones <jim.jones@uni-muenster.de>
Author: Daniil Davydov <3danissimo@gmail.com>
Co-authored-by: Alexander Korotkov <aekorotkov@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Soumya S Murali <soumyamurali.work@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAJDiXghdFcZ8%3Dnh4G69te7iRr3Q0uFyXxb3ZdG09_GTNZXwH0g%40mail.gmail.com
Backpatch-through: 17 M src/backend/storage/aio/read_stream.c
M src/backend/storage/buffer/bufmgr.c
M src/include/utils/rel.h
M src/test/modules/test_misc/t/013_temp_obj_multisession.pl
Add tests for cross-session temp table access
commit : 40927d458fe1a8c96bcf418b47169f0f6eb15946
author : Alexander Korotkov <akorotkov@postgresql.org>
date : Thu, 14 May 2026 12:21:03 +0300
committer: Alexander Korotkov <akorotkov@postgresql.org>
date : Thu, 14 May 2026 12:21:03 +0300 Add a TAP test in src/test/modules/test_misc that documents what
happens when one session attempts to read or modify another session's
temporary table. This commit only adds tests; it does not change
backend behavior, so the assertions reflect current behavior:
- SELECT, UPDATE, DELETE, MERGE, COPY on a table without an index
silently succeed with no error and zero rows / zero affected rows.
These commands run through the read-stream path, which currently
bypasses the RELATION_IS_OTHER_TEMP() check. This is the
underlying bug to be fixed in a follow-up.
- INSERT errors with "cannot access temporary tables of other
sessions" because hio.c calls ReadBufferExtended() to find a page
with free space and is caught by the existing check there.
- Index scan errors via the same existing check, reached through
nbtree -> ReadBuffer -> ReadBufferExtended.
- TRUNCATE / ALTER TABLE / ALTER INDEX / CLUSTER fail with their
command-specific error messages.
- VACUUM is silently skipped to avoid noise during database-wide
VACUUM (vacuum_rel() returns without warning).
- DROP TABLE is intentionally allowed: DROP does not touch the
table's contents, and autovacuum relies on this to clean up
temp relations orphaned by a crashed backend.
- ALTER FUNCTION / DROP FUNCTION on an owner-created function over
its own temp row type work as catalog operations -- they don't
read the underlying data.
- CREATE FUNCTION from a separate session, using another session's
temp row type as an argument, is allowed but emits a NOTICE: the
function is moved into the creator's pg_temp namespace with an
auto-dependency on the borrowed type, so it disappears together
with the session that created it.
- A bare DROP TABLE on a temp table that has a cross-session
dependent function fails with a catalog-level dependency error.
- LOCK TABLE in ACCESS SHARE mode on another session's temp table
succeeds and properly blocks the owner's session-exit cleanup
(which acquires AccessExclusiveLock via findDependentObjects).
This exercises the same LockRelationOid path used by autovacuum
when cleaning up orphaned temp relations.
- When the owner session ends, the normal session-exit cleanup
cascades through DEPENDENCY_NORMAL and removes both the temp
objects and any cross-session functions that depended on them.
Also, document the contract for RELATION_IS_OTHER_TEMP() so that
future buffer-access entry points enforce the same rule.
Backpatch this through PostgreSQL 17, where b7b0f3f27241 introduces a code
path bypassing this check.
Author: Jim Jones <jim.jones@uni-muenster.de>
Author: Daniil Davydov <3danissimo@gmail.com>
Co-authored-by: Alexander Korotkov <aekorotkov@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Soumya S Murali <soumyamurali.work@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAJDiXghdFcZ8%3Dnh4G69te7iRr3Q0uFyXxb3ZdG09_GTNZXwH0g%40mail.gmail.com
Backpatch-through: 17 M src/include/utils/rel.h
M src/test/modules/test_misc/meson.build
A src/test/modules/test_misc/t/013_temp_obj_multisession.pl
pgbench: fix verbose error message corruption with multiple threads
commit : 52b3e7001cb3584ae9f95ac01a185a50cca988cb
author : Fujii Masao <fujii@postgresql.org>
date : Thu, 14 May 2026 12:30:34 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Thu, 14 May 2026 12:30:34 +0900 When pgbench runs with multiple threads and verbose error reporting is
enabled (--verbose-errors), multiple clients can build verbose error
messages concurrently. Previously, a function-local static
PQExpBuffer was used for these messages, causing the buffer to be
shared across threads. This was not thread-safe and could result in
corrupted or incorrect log output.
Fix this by using a local PQExpBufferData instead of a static buffer.
This keeps verbose error messages correct during concurrent execution.
Backpatch to v15, where this issue was introduced.
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Alex Guo <guo.alex.hengchen@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwER1AjGXpkKB9t9820NBhMQ_Ghv7=HsKeodUr3=SZsF4g@mail.gmail.com
Backpatch-through: 15 M src/bin/pgbench/pgbench.c
Add more tests for corrupted data with pglz_decompress()
commit : 54eeefaedbee0385529f3edf321bb99e49232aaa
author : Michael Paquier <michael@paquier.xyz>
date : Wed, 13 May 2026 14:43:47 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Wed, 13 May 2026 14:43:47 +0900 Two cases fixed by 2b5ba2a0a141 were not covered, to emulate the
handling of corrupted data, for:
- set control bit with a valid 2-byte match tag where offset is 0.
- set control bit with a valid 2-byte match tag where offset exceeds
output written.
Oversight in 67d318e70402.
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/agF4xkIdRcrCIprs@paquier.xyz
Backpatch-through: 14 M src/test/regress/expected/compression_pglz.out
M src/test/regress/sql/compression_pglz.sql
Fix stale COPY progress during logical replication table sync
commit : f2acab53482cfd444c8ac23d317f90ad6f6b1a7f
author : Fujii Masao <fujii@postgresql.org>
date : Wed, 13 May 2026 11:44:31 +0900
committer: Fujii Masao <fujii@postgresql.org>
date : Wed, 13 May 2026 11:44:31 +0900 Previously, pg_stat_progress_copy in the subscriber could continue to show
the initial COPY operation for logical replication table synchronization as
active even after the data copy had finished. The stale progress entry
remained visible until synchronization caught up with the publisher.
This happened because the table synchronization code called BeginCopyFrom()
and CopyFrom(), but failed to call EndCopyFrom() afterward.
This commit fixes the issue by adding the missing EndCopyFrom() call so that
the COPY progress state in the subscriber is cleared as soon as the initial
data copy completes.
Backpatch to all supported branches.
Author: Shinya Kato <shinya11.kato@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: ChangAo Chen <cca5507@qq.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAOzEurQKuy3RiPkd=25PEwEzaqHuGvEOf=X7vaVzhgNjaukYzA@mail.gmail.com
Backpatch-through: 14 M src/backend/replication/logical/tablesync.c
Add missing include in Cluster.pm
commit : eb5559b7df98581bd9a5142433122d1ba076d568
author : Michael Paquier <michael@paquier.xyz>
date : Tue, 12 May 2026 16:44:28 +0900
committer: Michael Paquier <michael@paquier.xyz>
date : Tue, 12 May 2026 16:44:28 +0900 The postmaster test 004_negotiate.pl could fail due to IO::Socket::INET
gone missing, in environments that cannot use Unix sockets.
Oversight in the backport done in 6dffaeb8e54c, so like the other commit
this is applied across the v14~17 range. Per buildfarm member drongo.
Security: CVE-2026-6479
Backpatch-through: 14 M src/test/perl/PostgreSQL/Test/Cluster.pm