PostgreSQL 18.5 commit log

Stamp 18.6.

commit   : 724edf9bde9d356724ad384a2e196edc3c9f80f7    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Tue, 11 Aug 2026 14:38:31 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Tue, 11 Aug 2026 14:38:31 -0400    

Click here for diff

M configure
M configure.ac
M meson.build

Release notes for 18.6.

commit   : 841d0cb0f9b8b1b25e7b299ac0eb134074b45a08    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Tue, 11 Aug 2026 14:37:01 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Tue, 11 Aug 2026 14:37:01 -0400    

Click here for diff

Farewell, 18.5; we hardly knew ye.  

M doc/src/sgml/release-18.sgml

Fix pg_strupper/lower/title/fold() functions to work with C locale

commit   : 5f003855e7f05bd03c5531a58838540f62b8b19e    
  
author   : Heikki Linnakangas <heikki.linnakangas@iki.fi>    
date     : Tue, 11 Aug 2026 21:18:45 +0300    
  
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>    
date     : Tue, 11 Aug 2026 21:18:45 +0300    

Click here for diff

Starting with commit 011384ba45, calling to_date() or to_timestamp()  
with "TMMonth" or other TM-prefixed format keyword, with the C locale,  
would crash.  
  
In REL_19_STABLE and above, pg_strupper(), pg_strlower(),  
pg_strtitle(), and pg_strfold() functions have a special case for the  
C locale, but that was missing in REL_18_STABLE.  On REL_18_STABLE,  
the functions call the libc function even in C locale, even though the  
native locale object is NULL.  On Linux, the underlying libc functions  
will crash when called with NULL locale.  (On macOS, they reportedly  
do not, but even then it's not clear if they will do what you'd  
expect.)  
  
This went unnoticed because until commit 011384ba45, we never called  
these functions in C locale, all the callers had a special codepath  
for C locale.  We could add a special path in the new callers too, but  
it's an accident waiting to happen, so let's backport the C  
locale-specific handling from REL_19_STABLE to REL_18_STABLE.  Older  
versions did not have these functions at all, hence no problem.  
  
This applies to REL_18_STABLE only.  
  
Reported-by: Masashi Kamura <kamura.masashi@fujitsu.com>  
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>  
Discussion: https://www.postgresql.org/message-id/OS9PR01MB1317436E07D06281AD1A0452F94DD2%40OS9PR01MB13174.jpnprd01.prod.outlook.com  

M src/backend/utils/adt/pg_locale.c

Stamp 18.5.

commit   : 17fae4fbdd677b5a2e712734ed5ef21c052b68a3    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 16:52:29 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 16:52:29 -0400    

Click here for diff

M configure
M configure.ac
M meson.build

Update .abi-compliance-history for security fixes.

commit   : e35db2cd88da91391c55670d17e275085478f2de    
  
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    

Click here for diff

Security: CVE-2026-6470, CVE-2026-6471, CVE-2026-6469  

M .abi-compliance-history

Last-minute updates for release notes.

commit   : cf6c2adec81358460d38ece9be9b9dbe0309927d    
  
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    

Click here for diff

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-18.sgml

psql: Don't do backquote expansion in \unrestrict.

commit   : 71ca694c73cd1a808a393b2d5076e0518404468e    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    

Click here for diff

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   : 4c5128ca0b308c37a91ea7dcc4c10a98c672d592    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    

Click here for diff

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   : fe32b10fca5342b9f86848a55288f6143b3afa04    
  
author   : Daniel Gustafsson <dgustafsson@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    

Click here for diff

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
M doc/src/sgml/pgcrypto.sgml

Fix out-of-bound reads with ascii() for invalid multibyte characters

commit   : 08e812c02ae14bbfb03d787884e4c6087419ecf7    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    

Click here for diff

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   : 29921259e83b613a14d71d8b26fd5d0419944297    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    

Click here for diff

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_stored.sql
M src/test/regress/sql/generated_virtual.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   : 900894d35ca72bfba853447ca986bdced4ad993b    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    

Click here for diff

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   : 0b12f56bfac12e5930ee22071722082b0a45346b    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:13 -0700    

Click here for diff

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   : 57f59ca1d954f2de7ac3ef8971046778c955613a    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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   : 2780538433fc3b40b4e1e7bc7cbd350e37b6d550    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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   : 2e91f8548daa7c7c7d5848f3812fac95fe9e9db5    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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   : e88eb4e766381070f42e5b84e583a1d0288983f7    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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   : 37b8f3b0e05e85d4338f04c71caa156ba21d5015    
  
author   : Robert Haas <rhaas@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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   : 2a29b607dbbba47c8e1c97458708e775bfa0e9bb    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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 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   : 82fd688012954d8254b6e14ead997eb0e9223d86    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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   : 0a61fcde03257739d59d9b96e4c77f6c65e070e3    
  
author   : Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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 contrib/amcheck/verify_common.c
M src/backend/utils/init/usercontext.c

Use value of scram_iterations in mock_scram_secret().

commit   : 822143c4d1dce62a43b98341eacbd4429eca7e59    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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   : 0ddd9098a310ed711c6cba758c06dfe38f9654ff    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

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

Fix multirange type handling in pg_restore_attribute_stats()

commit   : 08454e8b2defdf8a0b61e550606f78b8f184f2e6    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

statatt_get_type() unconditionally converted multirange types to their  
underlying range type.  This choice affected all the type information,  
like atttypid, atttyptype and operators.  
  
This made the bounds histogram work correctly (range type is required),  
but it was wrong for all the other stat kinds.  MCV values for a  
multirange column should be parsed as multirange arrays, not range  
arrays.  It also made the TYPTYPE_MULTIRANGE check for the range stats  
validation as dead code, since atttyptype was always TYPTYPE_RANGE  
after the conversion due to the centralized statatt_get_type().  
  
pg_restore_extended_stats() handles the same case correctly: it keeps  
the original type and explicitly converts to the range type only at the  
point where range_histogram_bounds is built.  
  
The fix of this issue is simple: the multirange-to-range conversion  
needs to be moved from the centralized statatt_get_type() up to where  
attribute stats build their range_histogram_bounds, matching what is  
done for extended statistics restore.  
  
The regression tests for multiranges with attribute stats are extended  
to cover this case.  
  
Author: OpenAI Security Research Team  
Backpatch-through: 18  
Security: CVE-2026-16238  

M src/backend/statistics/attribute_stats.c
M src/test/regress/expected/stats_import.out
M src/test/regress/sql/stats_import.sql

Add test with multirange type for pg_restore_attribute_stats()

commit   : 8d428c6e677d05122ad2286f0e8d468bb532acb1    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:12 -0700    

Click here for diff

This commit adds a test for pg_restore_attribute_stats() with the  
injection of statistics related to a multirange type.  This case is  
supported in statatt_get_type() since its introduction in ce207d2a7901,  
but there was no test in the main regression test suite to check for the  
case where attribute stats is restored for a multirange type, as done by  
multirange_typanalyze().  
  
Note that this has been originally applied as d4504d6f60e0 in v19 and  
newer branches.  This will be used for the test of a follow-up commit.  
  
Author: Corey Huinker <corey.huinker@gmail.com>  
Discussion: https://postgr.es/m/CADkLM=c3JivzHNXLt-X_JicYknRYwLTiOCHOPiKagm2_vdrFUg@mail.gmail.com  
Security: CVE-2026-16238  
Backpatch-through: 18  

M src/test/regress/expected/stats_import.out
M src/test/regress/sql/stats_import.sql

Reject GSSEncRequest after direct SSL connection

commit   : 203a48209aa4179d2419fa3243b07998f0373d0a    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : a14ba29b15a8b342808702e9da3e4a4532044f61    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : 028ee716a7902bd2a68843a5d317a6821a0500e2    
  
author   : Heikki Linnakangas <heikki.linnakangas@iki.fi>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : 849019a50a0ccbc7a7fe2ab3db53078ec2f99131    
  
author   : Heikki Linnakangas <heikki.linnakangas@iki.fi>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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

pg_stat_statements: Fix buffer overflow with query normalization

commit   : 8a31ffc2d4cc5e2f3fb42b6a41b7db802716615d    
  
author   : Álvaro Herrera <alvherre@kurilemu.de>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

Since commit 62d712ecfd94, pg_stat_statements has been underestimating  
the size of the result buffer possible for a normalized query, in cases  
where the query includes many squashable lists, causing the normalized  
query to write past the allocated area.  
  
The allocated buffer size forgot to account for the comment appended in  
a squashable list, "/*, ... */".  Instead of trying to track down  
precisely how much space we need, fix by switch to using an expansible  
StringInfo.  This not only fixes the bug, but it also makes the code  
simpler to follow.  
  
Author: Álvaro Herrera <alvherre@kurilemu.de>  
Reported-by: Sajeeb Lohani with TrendAI Zero Day Initiative  
Reported-by: Yuelin Wang <3020001251@tju.edu.cn>  
Diagnosed-by: Michaël Paquier <michael@paquier.xyz>  
Backpatch-through: 18  
Security: CVE-2026-14676  
Discussion: https://postgr.es/m/19528-7290dd7e6f7dcc22@postgresql.org  

M contrib/pg_stat_statements/pg_stat_statements.c

Preserve the owner of extended statistics rebuilt by ALTER TABLE.

commit   : a1fa24127d6a24611e5ec8e5b00584b333a3a06c    
  
author   : Masahiko Sawada <msawada@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : 722695db18b6540a3757811436116f928c71b763    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : 54649de65f0822ee0678cc2b2df6ad47de0a748e    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : 2a03f21daf59c6d00a01d553b75bb74448a9593d    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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/cache/funccache.c
M src/backend/utils/fmgr/funcapi.c
M src/pl/tcl/pltcl.c

pg_dump: avoid assuming how long pg_proc.protrftypes can be.

commit   : 3392cce5c92ea4c84b8a5088b4717066fd280056    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : 7f0e1aac7a7b54b6b575a3b4d6c90088dd90c38b    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : a2cb5a1cfbae3c002f382ec22781c8f7c284f9d0    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : 87c4b821972c9b66ced5520636c8ad4b60f8fd81    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:11 -0700    

Click here for diff

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   : b7e5c3f63464211f055d21f4f5196afa5905af8f    
  
author   : Masahiko Sawada <msawada@postgresql.org>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    

Click here for diff

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   : dddc8a69ff8bde575ce950e9074439ccfd975336    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    

Click here for diff

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   : e251350573e2ceb846b3b992f483d2d0de7a8a20    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    

Click here for diff

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   : 4fafe23805c4c75c2e85e8a0c1675fd17d92977b    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    
  
committer: Noah Misch <noah@leadboat.com>    
date     : Mon, 10 Aug 2026 06:38:10 -0700    

Click here for diff

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   : 3d3462a6d9c719591e2f130318bc3f00ba837e41    
  
author   : Peter Eisentraut <peter@eisentraut.org>    
date     : Mon, 10 Aug 2026 12:14:04 +0200    
  
committer: Peter Eisentraut <peter@eisentraut.org>    
date     : Mon, 10 Aug 2026 12:14:04 +0200    

Click here for diff

Source-Git-URL: https://git.postgresql.org/git/pgtranslation/messages.git  
Source-Git-Hash: cebe759464bfe8207fc3d3c2a0c6f79474fb4d1c  

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/initdb/po/sv.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_rewind/po/sv.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/ecpglib/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   : a4c41bbcc7b0aed721950303338d75b09eddc295    
  
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    

Click here for diff

M doc/src/sgml/release-18.sgml

First-draft release notes for 18.5.

commit   : 828d602f21156de916397b5df52397f18da7f759    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Fri, 7 Aug 2026 13:11:52 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Fri, 7 Aug 2026 13:11:52 -0400    

Click here for diff

As usual, the release notes for other branches will be made by cutting  
these down, but put them up for community review first.  

M doc/src/sgml/release-18.sgml

Fix hot standby accepting connections too early after a crash reset

commit   : 311e66df9cc857dcbb02024270f5130815682d63    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Sat, 8 Aug 2026 00:09:05 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Sat, 8 Aug 2026 00:09:05 +0900    

Click here for diff

Commit b53b88109f9 made the postmaster maintain reachedConsistency in  
addition to the startup process.  Since the startup process is forked  
from the postmaster, it begins life holding whatever value the  
postmaster last set.  
  
On a crash reset the postmaster re-forks the startup process while its  
own copy still says true: it clears that copy only on receipt of  
PMSIGNAL_RECOVERY_STARTED, which the replacement process cannot send  
before it exists.  The replacement therefore starts out believing the  
database is already consistent.  
  
CheckRecoveryConsistency() then skips the minRecoveryPoint comparison  
altogether, so hot standby is announced at redo start while replay may  
be arbitrarily far behind minRecoveryPoint.  Read-only connections are  
accepted and answer from heap pages that were flushed ahead of the  
replay position, returning wrong results with no error raised.  The  
same branch also runs XLogCheckInvalidPages() and  
CheckTablespaceDirectory(), which are skipped as well, and  
log_invalid_page() treats page references that are normal before  
consistency as a PANIC.  
  
Fix by clearing reachedConsistency in InitWalRecovery(), so that a  
startup process never depends on the value it inherited.  The  
postmaster's own copy is deliberately left alone: forked backends read  
it to choose the "not yet accepting connections" errdetail, and it  
converges once the new startup process sends PMSIGNAL_RECOVERY_STARTED  
and, on reaching minRecoveryPoint, PMSIGNAL_RECOVERY_CONSISTENT.  
  
Successive crash resets alternate.  A startup process that skips the  
branch never sends PMSIGNAL_RECOVERY_CONSISTENT, so the postmaster's  
copy stays false and the next reset forks a process holding the correct  
value; that pass reaches consistency properly, which sets the  
postmaster's copy back to true and re-arms the problem for the reset  
after it.  Roughly every other crash reset is therefore affected, not  
just the first one.  EXEC_BACKEND builds are unaffected, as  
reachedConsistency is not carried in BackendParameters.  
  
Backpatch to v18, where commit b53b88109f9 introduced this issue.  
  
Reported-by: Eric Ridge <eebbrr@planetscale.com>  
Author: Nikhil Sontakke <nikhil@planetscale.com>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/CA+UBoq2n2Zg9rKgMfUtUohzGssisF9cDeyjKqPrnRNFprEyX1Q@mail.gmail.com  
Backpatch-through: 18  

M src/backend/access/transam/xlogrecovery.c

Only clear VACUUM's read stream strategy once in failsafe mode

commit   : 7c25cdb1ebf64b1e1c9053ca27f9552c9a528a12    
  
author   : Melanie Plageman <melanieplageman@gmail.com>    
date     : Fri, 7 Aug 2026 09:59:55 -0400    
  
committer: Melanie Plageman <melanieplageman@gmail.com>    
date     : Fri, 7 Aug 2026 09:59:55 -0400    

Click here for diff

112c2683807b4d690 restored failsafe vacuum's abandonment of a buffer  
access strategy by clearing the ReadBuffersOperations' strategy  
references. But it did so in lazy_scan_heap()'s main loop, meaning it  
looped through all the ReadBuffersOperations once per block after  
failsafe was engaged. Track it with a local flag and clear the strategy  
only once.  
  
Reported-by: Melanie Plageman <melanieplageman@gmail.com>  
Discussion: https://postgr.es/m/CAAKRu_Zse14nSNeCgtnE1LUAH8Of7OmYR%2BCc3O_DAzxt3m6T-g%40mail.gmail.com  
Backpatch-through: 18  

M src/backend/access/heap/vacuumlazy.c

Drain pending asynchronous requests during ExecReScanAppend.

commit   : 4ea497a9263efe17d809b844a8cc0c71e99f5cc4    
  
author   : Etsuro Fujita <efujita@postgresql.org>    
date     : Fri, 7 Aug 2026 17:30:02 +0900    
  
committer: Etsuro Fujita <efujita@postgresql.org>    
date     : Fri, 7 Aug 2026 17:30:02 +0900    

Click here for diff

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   : 2fd8d45ecf7cee94613483f073c821b8834426c7    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Fri, 7 Aug 2026 14:23:35 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Fri, 7 Aug 2026 14:23:35 +0900    

Click here for diff

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

Restore vacuum failsafe abandonment of buffer access strategy

commit   : 585181e077486324e12f6071a70955a0a48906aa    
  
author   : Melanie Plageman <melanieplageman@gmail.com>    
date     : Thu, 6 Aug 2026 17:16:23 -0400    
  
committer: Melanie Plageman <melanieplageman@gmail.com>    
date     : Thu, 6 Aug 2026 17:16:23 -0400    

Click here for diff

VACUUM's wraparound failsafe mode exists to reclaim transaction IDs as  
quickly as possible. 4830f1024325 made the failsafe stop using the  
BAS_VACUUM buffer access strategy so that the rest of the vacuum could  
make use of all of shared buffers rather than being confined to the  
small strategy ring.  
  
However, when 9256822608f3 made vacuum's first heap pass use the read  
stream, this was accidentally disabled. The read stream keeps its own  
references to the buffer access strategy, so clearing vacrel->bstrategy  
in lazy_check_wraparound_failsafe() no longer had any effect on the  
reads issued by the first pass.  
  
Fix this by adding clearing the BufferAccessStrategy reference actually  
being used by the ongoing scan -- those in the ReadBuffersOperations  
structs themselves.  
  
Two things we accept rather than fix, as neither is worth the added  
complexity given how rarely failsafe mode is reached:  
  
- A small amount of read time for IOs that were already in progress when  
  the strategy was cleared may be attributed to IOCONTEXT_NORMAL instead  
  of IOCONTEXT_VACUUM. WaitReadBuffers() derives the IOContext from the  
  (now cleared) strategy, so the wait time of these in-flight IOs is  
  misattributed. This is bounded by the stream's look-ahead window and  
  happens at most once per vacuum, when the strategy is first cleared.  
  
- The stream's buffer pin limit stays lower than it would have been had  
  no strategy been used at all. max_pinned_buffers is capped by the  
  strategy's pin limit when the stream is created and is not recomputed  
  when the strategy is cleared. Raising it would mean building a new,  
  larger ring, which would require first waiting for all in-progress IOs  
  to complete. That didn't seem worth it.  
  
Reported-by: Jingtang Zhang <mrdrivingduck@gmail.com>  
Discussion: https://postgr.es/m/CAPsk3_APRYVLhAJ5TMwdmpSx8W_%3DPHMm%3DPmKAvnC3gBrfNommQ%40mail.gmail.com  
Backpatch-to: 18  

M src/backend/access/heap/vacuumlazy.c
M src/backend/storage/aio/read_stream.c
M src/include/storage/read_stream.h

Fix race condition in subscription TAP test 023_twophase_stream.

commit   : b37f14875a284b7bf3c5ec2e3691aa5d8bf8e736    
  
author   : Amit Kapila <akapila@postgresql.org>    
date     : Thu, 6 Aug 2026 11:26:57 +0530    
  
committer: Amit Kapila <akapila@postgresql.org>    
date     : Thu, 6 Aug 2026 11:26:57 +0530    

Click here for diff

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

Make local buffers pin limit more conservative

commit   : ed8050370b7cf117dfb0de218695b1e003a51f36    
  
author   : Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 5 Aug 2026 11:44:01 -0400    
  
committer: Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 5 Aug 2026 11:44:01 -0400    

Click here for diff

GetLocalPinLimit() and GetAdditionalLocalPinLimit(), currently in use  
only by the read stream, previously allowed a backend to pin all  
num_temp_buffers local buffers. This meant that the read stream could  
use every available local buffer for read-ahead, leaving none for other  
concurrent pin-holders.  
  
In 18, this was reported as a sequential scan of a temporary table  
failing with "no empty local buffer available": with  
effective_io_concurrency >= 64 and default io_combine_limit and  
temp_buffers, the scan's read stream budget,  
(effective_io_concurrency + 1) * io_combine_limit, meets or exceeds  
num_temp_buffers, so look-ahead could pin the entire local buffer pool.  
Any additional pin request made while returning tuples -- such as  
fetching TOASTed values from the table's (also temporary) TOAST table --  
then found no unpinned buffer to evict.  
  
Cap the local pin limit to num_temp_buffers / 4, providing some  
headroom. This doesn't guarantee that all needed pins will be available  
-- for example, a backend can still open more cursors than there are  
buffers -- but it makes it less likely that read-ahead will exhaust the  
pool.  
  
This is a backpatch of commit da6874635db, which was applied to master  
only during the 19 development cycle, where the issue surfaced as a  
regression test failure after on-access pruning began setting the  
visibility map. Reports of the failure above on 18 prompted  
backpatching it now.  
  
No backpatch to 17, even though its read stream also allows a single  
stream to pin the whole pool in principle. There, sequential scans pass  
READ_STREAM_SEQUENTIAL, which disables fadvise-based look-ahead, so the  
look-ahead distance cannot grow past io_combine_limit (at most 32  
buffers, versus a minimum temp_buffers of 100) and the reported failure  
is unreachable. The remaining theoretical paths require adversarial  
settings and have never been reported. Moreover, 17 predates these  
functions; the fix would have to be reimplemented in  
LimitAdditionalLocalPins(), making the change not a simple cherry-pick.  
  
Reported-by: Induja Sreekanthan <indujas@google.com>  
Reported-by: Eduard Stepanov <crtxcz@gmail.com>  
Reported-by: Feike Steenbergen <feikesteenbergen@gmail.com>  
Reported-by: Alexander Lakhin <exclusion@gmail.com>  
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>  
Reviewed-by: Andres Freund <andres@anarazel.de>  
Discussion: https://postgr.es/m/97529f5a-ec10-46b1-ab50-4653126c6889%40gmail.com  
Discussion: https://postgr.es/m/flat/CAFMO8-rYPSJbXsDdWDzDdpNi-fQ%2B6bKvgbXwE%2BR%3DsGko4epq0Q%40mail.gmail.com  
Backpatch-through: 18  

M src/backend/storage/buffer/localbuf.c

Fix calculating length of match to localized month/weekday names

commit   : 011384ba45fe193131f92c2d16c45f20d909301d    
  
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    

Click here for diff

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   : 13a9be148e530b9b5c0af2b499e3a08c1f5eb053    
  
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    

Click here for diff

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   : 19f0391df48202e2c6ac2e30a4c1c284aab5681b    
  
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    

Click here for diff

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 error handling in getCopyDataMessage() and pqFunctionCall3()

commit   : 6b46a5d1b6164f2fdb15229dea9f3ed94ef20760    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Tue, 4 Aug 2026 17:03:27 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Tue, 4 Aug 2026 17:03:27 +0900    

Click here for diff

Commit f6f0542266f0 changed getNotify(),  
getParameterStatus(), and related libpq message-processing paths to  
abandon the connection on out-of-memory errors.  
  
However, getCopyDataMessage() and pqFunctionCall3() did not handle  
this new fatal-error state. Both can process asynchronous  
NotificationResponse and ParameterStatus messages while waiting for  
other responses. If one of those messages triggered a fatal error, these  
loops continued processing instead of reporting it immediately.  
  
Fix this by checking for a saved fatal error after processing an  
asynchronous message. If the connection has been abandoned, return the  
appropriate error immediately instead of continuing to parse input.  
  
Backpatch to v18, where commit f6f0542266f0 introduced this issue.  
  
Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>  
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/CAO6_XqpGfm+XHE1OzS=_+jroeDOxhhGa11P3cbm9q2gT05yorA@mail.gmail.com  
Backpatch-through: 18  

M src/interfaces/libpq/fe-protocol3.c

Fix ALTER COLUMN ... DROP EXPRESSION with subpartitions

commit   : c374f2807c236dd8fb4bee9f4ebfe4af300491f9    
  
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    

Click here for diff

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_stored.out
M src/test/regress/sql/generated_stored.sql

Fix missing money overflow checks for INT64_MIN / -1

commit   : 6298a41b4e34773dbc0c50c26de825a4efe31f07    
  
author   : David Rowley <drowley@postgresql.org>    
date     : Tue, 4 Aug 2026 18:00:27 +1200    
  
committer: David Rowley <drowley@postgresql.org>    
date     : Tue, 4 Aug 2026 18:00:27 +1200    

Click here for diff

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   : bf048f0e17a1ea82dc22c8ad446d14670b52451c    
  
author   : David Rowley <drowley@postgresql.org>    
date     : Tue, 4 Aug 2026 16:09:55 +1200    
  
committer: David Rowley <drowley@postgresql.org>    
date     : Tue, 4 Aug 2026 16:09:55 +1200    

Click here for diff

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   : a0daa0b4127dffe99a92c6606ad778f89ec3239f    
  
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    

Click here for diff

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   : 9a8c9338377c397714bb2cc44b46a430dce5bdfe    
  
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    

Click here for diff

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

Remove unused arg and dead code in set_attnotnull()

commit   : d04a24d9ead0d47f772d5a416813259af5a36e98    
  
author   : Álvaro Herrera <alvherre@kurilemu.de>    
date     : Mon, 3 Aug 2026 13:52:41 +0200    
  
committer: Álvaro Herrera <alvherre@kurilemu.de>    
date     : Mon, 3 Aug 2026 13:52:41 +0200    

Click here for diff

The is_valid parameter was never referenced in the function body, and  
the 'thisatt' local variable is set but never used.  Remove both.  
  
Oversight in a379061a22a8.  
  
Author: Sami Imseih <samimseih@gmail.com>  
Backpatch-through: 18  
Discussion: https://postgr.es/m/CAA5RZ0tHnvSrfUy4jWJchjvkL_aJe0hCnZpMsFRdLrSxCne5qQ@mail.gmail.com  

M src/backend/commands/tablecmds.c

Tighten up TS dictionary cache entry creation.

commit   : 81b1e79166a524b95628f8d459571f1b029fe19e    
  
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    

Click here for diff

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   : 4689ea9ceee362efe2569cd3b0e5c7072a8a24bc    
  
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    

Click here for diff

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   : 5f67124fa43448702acc0f9448e0ad118fe5e791    
  
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    

Click here for diff

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

libpq-oauth: Avoid overflow for very large intervals

commit   : 74169d3a1d695556ad81ef7a9c256daf0d554da1    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Fri, 31 Jul 2026 11:19:44 -0700    
  
committer: Jacob Champion <jchampion@postgresql.org>    
date     : Fri, 31 Jul 2026 11:19:44 -0700    

Click here for diff

The slow_down interval parsing code checks explicitly for overflow, but  
since it does that after the signed overflow has already occurred, we  
end up inviting undefined behavior from the compiler anyway.  
  
Use checked arithmetic instead. set_timer() takes a long int in order to  
interface nicely with libcurl, so use an int32 as the interval counter  
and clamp to LONG_MAX during conversion to milliseconds.  
  
Backpatch to 18, where libpq-oauth was introduced.  
  
Reported-by: Andres Freund <andres@anarazel.de>  
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>  
Discussion: https://postgr.es/m/qtclihmrkq67ach3xjxyi4qcksstin5qxwsnkqefkmotxwh4g6%40ae2bj6jvcmry  
Backpatch-through: 18  

M src/interfaces/libpq-oauth/oauth-curl.c

oauth: Add unit tests for multiplexer handling

commit   : fff8c86759659a070e014ffd7295e93a11a1479c    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Fri, 31 Jul 2026 11:19:37 -0700    
  
committer: Jacob Champion <jchampion@postgresql.org>    
date     : Fri, 31 Jul 2026 11:19:37 -0700    

Click here for diff

(This is a late cherry-pick of 4e1e41733, now that the new suite has  
proven its stability, to ensure coverage for this code in PG18 as the  
later branches diverge.)  
  
To better record the internal behaviors of oauth-curl.c, add a unit test  
suite for the socket and timer handling code. This is all based on TAP  
and driven by our existing Test::More infrastructure.  
  
This commit is a replay of 1443b6c0e, which was reverted due to  
buildfarm failures. Compared with that, this version protects the build  
targets in the Makefile with a with_libcurl conditional, and it tweaks  
the code style in 001_oauth.pl.  
  
Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>  
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>  
Discussion: https://postgr.es/m/CAOYmi+nDZxJHaWj9_jRSyf8uMToCADAmOfJEggsKW-kY7aUwHA@mail.gmail.com  
Discussion: https://postgr.es/m/CAOYmi+m=xY0P_uAzAP_884uF-GhQ3wrineGwc9AEnb6fYxVqVQ@mail.gmail.com  

M src/interfaces/libpq-oauth/Makefile
M src/interfaces/libpq-oauth/meson.build
A src/interfaces/libpq-oauth/t/001_oauth.pl
A src/interfaces/libpq-oauth/test-oauth-curl.c

Prevent walsummarizer from getting stuck at a timeline switch.

commit   : 18f0de6b885a017dfba620e0b9a5f42a1bc16d25    
  
author   : Robert Haas <rhaas@postgresql.org>    
date     : Fri, 31 Jul 2026 11:57:07 -0400    
  
committer: Robert Haas <rhaas@postgresql.org>    
date     : Fri, 31 Jul 2026 11:57:07 -0400    

Click here for diff

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   : 4cc49cb70396e5a0941eabbe9b23f9c4a3b85c3a    
  
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    

Click here for diff

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 Hash Join performance issue when hashing NULL values

commit   : f70acc8a2b96e0b565836799b6ccc3bacba8068a    
  
author   : David Rowley <drowley@postgresql.org>    
date     : Fri, 31 Jul 2026 23:24:46 +1200    
  
committer: David Rowley <drowley@postgresql.org>    
date     : Fri, 31 Jul 2026 23:24:46 +1200    

Click here for diff

adf97c156 allowed expression evaluation to perform hashing, and  
subsequently 9ca67658d fixed a memory stomping bug in that commit  
that caused unrelated-to-hashing expression op steps to stomp on the  
intermediate hash value.  The intermediate hash value needs to be  
maintained when hashing multiple hash keys.  9ca67658d didn't quite get  
things right when in "strict" mode when it aborted hashing early after  
encountering a NULL hash key.  What was meant to happen was that the  
expression returns NULL directly to indicate to the caller the value  
hashed to NULL.  The problem was that any EEOP_HASHDATUM_FIRST_STRICT or  
EEOP_HASHDATUM_NEXT32_STRICT op step that didn't belong to the final  
key to be hashed would have its op->resnull and op->resvalue pointing to  
the location to store the intermediate hash value.  That's correct for  
non-NULLs since we bit-rotate the intermediate value and continue hashing,  
but with the strict case, when we get a NULL key, we immediately jump to  
the "jumpdone" step.  The problem is the jumpdone step expects the  
ExprState resnull and resvalue fields to be set (as they would be if we  
didn't abort hashing early due to the NULL), but when we aborted early,  
the ExprState fields never got set.  This would result in inserting  
records into the hash table that would never match to any join partner,  
which is a waste of CPU and memory.  
  
Here we fix this by having EEOP_HASHDATUM_FIRST_STRICT and  
EEOP_HASHDATUM_NEXT32_STRICT populate the ExprState resnull and resvalue  
fields directly when the value to hash is NULL.  
  
Although Hash Agg and Hashed Subplans do use hashing from ExprStates,  
those were unaffected by this bug, as neither of those uses the STRICT op  
steps.  
  
Thanks to Tomas Vondra for finding the offending commit.  
  
Reported-by: Dan Stefura <dstefura@bluecatnetworks.com>  
Author: David Rowley <dgrowleyml@gmail.com>  
Discussion: https://postgr.es/m/YQBPR0101MB89738FB972FBD02A3640C6D3D6C92@YQBPR0101MB8973.CANPRD01.PROD.OUTLOOK.COM  
Backpatch-through: 18  

M src/backend/executor/execExprInterp.c
M src/backend/jit/llvm/llvmjit_expr.c

Fix issue with RANGE's DEFAULT partition pruning

commit   : 02e69be47c05c10c8ee8ac5d7634a4048c037ebc    
  
author   : David Rowley <drowley@postgresql.org>    
date     : Fri, 31 Jul 2026 15:37:42 +1200    
  
committer: David Rowley <drowley@postgresql.org>    
date     : Fri, 31 Jul 2026 15:37:42 +1200    

Click here for diff

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

Reject non-finite reltuples when restoring stats

commit   : a0369dd8448fba99d22068f533764bf2fb001278    
  
author   : Tomas Vondra <tomas.vondra@postgresql.org>    
date     : Thu, 30 Jul 2026 15:30:19 +0200    
  
committer: Tomas Vondra <tomas.vondra@postgresql.org>    
date     : Thu, 30 Jul 2026 15:30:19 +0200    

Click here for diff

When restoring relation stats, pg_restore_relation_stats() rejected  
calls with (reltuples < -1.0). But that is insufficient - Infinity and  
NaN values both pass that check, and get stored in pg_class verbatim.  
This can have various undesirable consequences.  
  
Fixed by rejecting non-finite reltuple values, in the same non-fatal way  
as for the existing checks (emit WARNING and skip the update). Adds a  
regression test to stats_import for these non-finite values, and to  
check the -1.0 special value is still accepted.  
  
Backpatch to 18, where pg_restore_relation_stats() was introduced.  
  
Patch by Jan Nidzwetzki, minor commit message tweaks by me.  
  
Author: Jan Nidzwetzki <jan@planetscale.com>  
Discussion: https://postgr.es/m/518BA772-8026-412A-AA8F-A7FE4C6B3717@planetscale.com  
Backpatch-through: 18  

M src/backend/statistics/relation_stats.c
M src/test/regress/expected/stats_import.out
M src/test/regress/sql/stats_import.sql

Initialize bs_reltuples in parallel GIN builds

commit   : d4420a97206cad5bcf63405062db5b4ebaa7f2b1    
  
author   : Tomas Vondra <tomas.vondra@postgresql.org>    
date     : Thu, 30 Jul 2026 14:06:20 +0200    
  
committer: Tomas Vondra <tomas.vondra@postgresql.org>    
date     : Thu, 30 Jul 2026 14:06:20 +0200    

Click here for diff

Index builds update pg_class.reltuples for the table. In parallel GIN  
builds, workers track the number of processed rows, and report it to  
the leader, who then updates the pg_class with a total. However,  
gin_parallel_build_main failed to initialize the bs_reltuples field,  
leaving it set to whatever happens to be on the stack (which may be  
bogus values like Infinity or NaN, or just impossibly high values).  
  
If such values get reported to the leader and stored in pg_class, that  
can have serious consequences. The pg_class.reltuples field is used to  
decide when a table is due for autovacuum or autoanalyze, and if it  
happens to be set to a bogus value, that may never happen. The field is  
also used by the optimizer when calculating costs.  
  
Fixed by initializing bs_reltuples together with the rest of the build  
state. The bs_numtuples was initialized later, but it seems cleaner to  
just initialize all the fields at once.  
  
After a bogus value gets persisted in pg_class, affected systems are  
unlikely to self-heal. That would require an ANALYZE, but preventing  
that is one of the consequences. We have considered forcing autoanalyze  
in these cases, but there's not a good way to reliably identify bogus  
values (except for a small minority like Infitiny/NaN).  
  
A manual ANALYZE on (possibly) affected tables is the only solution.  
  
Backpatch to 18, where parallel GIN builds were introduced.  
  
Reported-by: Jan Nidzwetzki <jan@planetscale.com>  
Discussion: https://postgr.es/m/518BA772-8026-412A-AA8F-A7FE4C6B3717@planetscale.com  
Backpatch-through: 18  

M src/backend/access/gin/gininsert.c

Skip SUBSCRIPTION TABLE TOC entries with --no-subscriptions.

commit   : 0abdb3e3610e171993e2951523a2d11284c23b7d    
  
author   : Amit Kapila <akapila@postgresql.org>    
date     : Thu, 30 Jul 2026 11:25:12 +0530    
  
committer: Amit Kapila <akapila@postgresql.org>    
date     : Thu, 30 Jul 2026 11:25:12 +0530    

Click here for diff

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   : 050e9d94d81bb1f6f5b34cb7794f201611fc9afa    
  
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    

Click here for diff

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   : 33101632235ad064b2bd7bc04a5066048dc48023    
  
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    

Click here for diff

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   : 277122036c3382c5ab47034a180fde1176728c43    
  
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    

Click here for diff

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   : b563fc6bd926fd9dca86d0c1a16fbf2e3e63dee9    
  
author   : Masahiko Sawada <msawada@postgresql.org>    
date     : Tue, 28 Jul 2026 12:33:35 -0700    
  
committer: Masahiko Sawada <msawada@postgresql.org>    
date     : Tue, 28 Jul 2026 12:33:35 -0700    

Click here for diff

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   : 73d63d1c1f676f4fcb289cdf9d052881719eb02f    
  
author   : Masahiko Sawada <msawada@postgresql.org>    
date     : Tue, 28 Jul 2026 10:39:43 -0700    
  
committer: Masahiko Sawada <msawada@postgresql.org>    
date     : Tue, 28 Jul 2026 10:39:43 -0700    

Click here for diff

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   : 7becb647da743fc3ca059181fef94419cd8167d6    
  
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    

Click here for diff

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   : e4527519b77e0f158e452fcbbcb2ac902d01ad44    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Tue, 28 Jul 2026 08:35:12 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Tue, 28 Jul 2026 08:35:12 +0900    

Click here for diff

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   : d560e730e813343b8d3f4a336244f2bc09ca84fc    
  
author   : Peter Geoghegan <pg@bowt.ie>    
date     : Sat, 25 Jul 2026 12:01:32 -0400    
  
committer: Peter Geoghegan <pg@bowt.ie>    
date     : Sat, 25 Jul 2026 12:01:32 -0400    

Click here for diff

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   : f2d6cf880240b1dcbb8791c2687b017bff23b156    
  
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    

Click here for diff

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   : bb0a3ca8d218b6c0792235d7306117e5bc36294a    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Thu, 23 Jul 2026 14:37:44 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Thu, 23 Jul 2026 14:37:44 +0900    

Click here for diff

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   : 1d299d6abfcdcd9400dd1e14b4213a9f39e41691    
  
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    

Click here for diff

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   : 545e2a9d74c3ccca3189e56a515a5793b782eb9b    
  
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    

Click here for diff

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   : 19e3aa704126f34f8fa4b36109478a7e6727a5e5    
  
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    

Click here for diff

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   : 9e40d07e140bc21186a8bdd1cb8b35d4d5f65979    
  
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    

Click here for diff

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   : 21f5e659e7587abf640f9c4aaff2238e3c3ff683    
  
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    

Click here for diff

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   : 959b7fa2cd603ec353aaef715993d0f0816febd2    
  
author   : Peter Geoghegan <pg@bowt.ie>    
date     : Fri, 17 Jul 2026 15:53:05 -0400    
  
committer: Peter Geoghegan <pg@bowt.ie>    
date     : Fri, 17 Jul 2026 15:53:05 -0400    

Click here for diff

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   : 125893ce83b8218db8446f5f6f416cdbf9e80f7b    
  
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    

Click here for diff

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   : aa572d521a1116b2c8902b98f44baf402a3e5246    
  
author   : Amit Kapila <akapila@postgresql.org>    
date     : Fri, 17 Jul 2026 09:33:16 +0530    
  
committer: Amit Kapila <akapila@postgresql.org>    
date     : Fri, 17 Jul 2026 09:33:16 +0530    

Click here for diff

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   : 8af1f527842170a257ae0684dd02907135d8d2e5    
  
author   : Peter Geoghegan <pg@bowt.ie>    
date     : Thu, 16 Jul 2026 18:55:33 -0400    
  
committer: Peter Geoghegan <pg@bowt.ie>    
date     : Thu, 16 Jul 2026 18:55:33 -0400    

Click here for diff

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

Reject infinite and out-of-range interval shifts in uuidv7().

commit   : c31b0fca059cf081679be1689b59b21912b0d29e    
  
author   : Masahiko Sawada <msawada@postgresql.org>    
date     : Thu, 16 Jul 2026 11:50:13 -0700    
  
committer: Masahiko Sawada <msawada@postgresql.org>    
date     : Thu, 16 Jul 2026 11:50:13 -0700    

Click here for diff

uuidv7(interval) shifts the current time by the given interval before  
encoding it into the 48-bit Unix-millisecond timestamp field of the  
generated UUID. Two cases were mishandled:  
  
An infinite interval ('infinity' or '-infinity') produced an infinite  
timestamp, which overflowed during the conversion to Unix-epoch  
microseconds and yielded a garbage UUID. Reject infinite intervals up  
front, before any timestamp arithmetic.  
  
A shift that moved the timestamp outside the range representable by  
the 48-bit field was silently accepted. Timestamps before the Unix  
epoch wrapped when cast to unsigned, and timestamps beyond  
approximately year 10889 overflowed the field; both produced UUIDs  
with bogus timestamps that break sort ordering. Reject any shifted  
timestamp outside the supported range.  
  
Also document that infinite intervals and out-of-range shifts are  
rejected.  
  
Although raising a new error changes behavior in a stable branch, this  
is back-patched to 18 (where uuidv7(interval) was introduced) because  
the previous behavior can silently corrupt data. Failing loudly is far  
safer than silently accepting the wraparound; otherwise users may not  
discover that their UUIDv7 values are no longer sortable until years  
later, when recovery is painful. It also matches how PostgreSQL  
already handles timestamp + interval overflow, which raises an  
error. The change only affects applications passing an interval large  
enough to push the result outside the representable range.  
  
Backpatch to 18, where uuidv7(interval) was introduced.  
  
Reported-by: Christophe Pettus <xof@thebuild.com>  
Author: Baji Shaik <baji.pgdev@gmail.com>  
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>  
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>  
Reviewed-by: Tristan Partin <tristan@partin.io>  
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>  
Discussion: https://www.postgresql.org/message-id/799A70FA-6E5C-4118-99EB-2FBBE1CBAC54@thebuild.com  
Backpatch-through: 18  

M doc/src/sgml/func.sgml
M src/backend/utils/adt/uuid.c
M src/test/regress/expected/uuid.out
M src/test/regress/sql/uuid.sql

postgres_fdw: stabilize terminated-connection regression tests

commit   : a00e43ac32d4f7367567791a68b2cf815f8c4d3f    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Fri, 17 Jul 2026 00:49:26 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Fri, 17 Jul 2026 00:49:26 +0900    

Click here for diff

The regression test for postgres_fdw_get_connections(true) assumed that  
a terminated remote connection would still remain visible in the FDW  
connection cache long enough to be reported as closed with a nonzero  
remote_backend_pid.  
  
That assumption is not always valid. postgres_fdw_get_connections()  
reports only entries that are still present in ConnectionHash, while  
pgfdw_inval_callback() may immediately discard an idle cached connection  
(xact_depth == 0) when a relevant invalidation arrives. In CI, that can  
happen between terminating the remote backend and querying  
postgres_fdw_get_connections(true), causing the function to return no  
rows.  
  
Adjust the idle-connection test to accept either outcome: if the cache  
entry is still present, verify that it reports the expected server name,  
closed status, and nonzero remote backend PID; otherwise treat zero rows  
as a legitimate result.  
  
To preserve coverage of the terminated-backend reporting path, add a  
separate check inside an explicit transaction. In that case, concurrent  
invalidation may mark the connection invalid but cannot discard it  
before transaction end, so postgres_fdw_get_connections(true) should  
still report the terminated connection as in-use, closed, and associated  
with a nonzero remote backend PID.  
  
Backpatch to v18, where the affected postgres_fdw_get_connections(true)  
test was introduced.  
  
Reported-by: Robert Haas <robertmhaas@gmail.com>  
Author: Fujii Masao <masao.fujii@gmail.com>  
Reviewed-by: Robert Haas <robertmhaas@gmail.com>  
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>  
Discussion: https://postgr.es/m/CA+Tgmoax3cHXHsm9OidN4F-xiu16y8q2W8T5dTNFic1Zoo2cOw@mail.gmail.com  
Backpatch-through: 18  

M contrib/postgres_fdw/expected/postgres_fdw.out
M contrib/postgres_fdw/sql/postgres_fdw.sql

commit   : 30c0442eb308cdb9a0d1b8551758775ec4d0e75d    
  
author   : Daniel Gustafsson <dgustafsson@postgresql.org>    
date     : Thu, 16 Jul 2026 16:05:36 +0200    
  
committer: Daniel Gustafsson <dgustafsson@postgresql.org>    
date     : Thu, 16 Jul 2026 16:05:36 +0200    

Click here for diff

Commit 67846550dc6d removed the xreflabels for initdb options, which  
turned the sentence "The second field contains the page checksum if  
data checksums are enabled" into "The second field contains the page  
checksum if -k are enabled", as well "Only has effect if data checksums  
are enabled" into "Only has effect if -k are enabled".  
  
Fix by setting an explicit link text, and while there also change the  
link to point to the data checksum page which has more information  
than just the initdb option.  
  
The original report was for one instance, further inspection turned  
up quite a few more cases.  Also redirect the link in the amcheck  
docs which albeit was reading right, but will be more helpful if  
linking to the main page on data checksums.  Backpatch to v18 where  
the xreflabels were removed.  
  
Author: Daniel Gustafsson <daniel@yesql.se>  
Reported-by: y.saburov@gmail.com  
Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at>  
Discussion: https://postgr.es/m/178350739237.73862.4549076173872335741@wrigleys.postgresql.org  
Backpatch-through: 18  

M doc/src/sgml/amcheck.sgml
M doc/src/sgml/config.sgml
M doc/src/sgml/storage.sgml

Check CREATE_REPLICATION_SLOT response shape in libpqwalreceiver

commit   : a6a2eb9f602490ca215371ba2497b07efccaace7    
  
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    

Click here for diff

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   : 4a4d6d1d1d997cb46b2931abb99a1a67e59cf5ca    
  
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    

Click here for diff

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   : 4d7feebfbd2f4ed84f95912be12225749ddf6e76    
  
author   : Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 15 Jul 2026 17:37:34 -0400    
  
committer: Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 15 Jul 2026 17:37:34 -0400    

Click here for diff

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   : f581fa729d8e108fef853c3156267b1f753d0210    
  
author   : Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 15 Jul 2026 17:37:34 -0400    
  
committer: Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 15 Jul 2026 17:37:34 -0400    

Click here for diff

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/heapam_xlog.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   : d0fb1da21bbcc7bdf13632cd080628757cd008e3    
  
author   : Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 15 Jul 2026 17:37:34 -0400    
  
committer: Melanie Plageman <melanieplageman@gmail.com>    
date     : Wed, 15 Jul 2026 17:37:34 -0400    

Click here for diff

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/backend/access/heap/heapam_xlog.c
M src/include/access/heapam_xlog.h

Include last block in FSM vacuum of bulk extended relation

commit   : eabc9a9dd908a1be7d66dc26b378b1488fd14847    
  
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    

Click here for diff

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   : a1b962b366210ab8d8d220582ad1c32620f35935    
  
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    

Click here for diff

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   : bcc428a23a69ee6f3bcc2ce20655da68eed0e7aa    
  
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    

Click here for diff

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

Fix argument names in pg_clear_attribute_stats() errors

commit   : ae8c4bd558c5d55c5a357e910d496eea8ff33647    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Wed, 15 Jul 2026 21:22:38 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Wed, 15 Jul 2026 21:22:38 +0900    

Click here for diff

pg_clear_attribute_stats() checks its required arguments manually  
because the function is not strict. Previously, when schemaname or  
relname was passed as NULL, the error incorrectly reported the  
argument name as "relation" in both cases:  
  
    ERROR:  argument "relation" must not be null  
  
This was misleading, especially for schemaname, and inconsistent with  
the function's SQL-visible argument names.  
  
The cause is that cleararginfo[] in attribute_stats.c used  
"relation" for both the schema-name and relation-name arguments.  
  
This commit fixes the issue by using "schemaname" and "relname" instead,  
matching the function's declared argument names so that the error reports  
the correct argument name.  
  
Backpatch to v18, where pg_clear_attribute_stats() was introduced.  
  
Author: Ilia Evdokimov <ilya.evdokimov@tantorlabs.com>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/4bf66c5e-8dd7-4ef3-8691-db67ecff6f16@tantorlabs.com  
Backpatch-through: 18  

M src/backend/statistics/attribute_stats.c

Include check on polpermissive relcache for policies

commit   : 36c6b499761878d40fd5f62b698546374a8aa5bc    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 15 Jul 2026 10:03:39 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 15 Jul 2026 10:03:39 +0900    

Click here for diff

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

Strip removed-relation references from PHVs in join clauses

commit   : 18105e6db5e5314a575fdb23a99cf4809d8ef062    
  
author   : Richard Guo <rguo@postgresql.org>    
date     : Wed, 15 Jul 2026 09:22:58 +0900    
  
committer: Richard Guo <rguo@postgresql.org>    
date     : Wed, 15 Jul 2026 09:22:58 +0900    

Click here for diff

Commit 9a60f295b stripped the stale PlaceHolderVars left behind by  
left-join removal from the surviving rels' baserestrictinfo and from  
EquivalenceClass member expressions, but it overlooked join clauses.  
A PlaceHolderVar embedded in a join clause can likewise retain the  
removed rel and join in its phrels, since remove_rel_from_query()  
fixes up the RestrictInfo's own relid sets but not the PHVs inside its  
expression.  
  
As before, this is normally harmless, because later processing  
consults those relid sets rather than the embedded PHVs.  However, a  
restriction clause derived from such an OR join clause inherits the  
stale PlaceHolderVar, and when the derived clause is translated for an  
appendrel child, pull_varnos() recomputes its relids and folds the  
removed relation back in.  The rebuilt clause then references a  
no-longer-existent relation, tripping an assertion during path  
generation.  
  
Fix by also stripping the removed relation from the PlaceHolderVars in  
the surviving rels' join clauses, including the sub-clauses of any OR  
clause.  
  
Like 9a60f295b, this is only reachable on v18 and later, where  
match_index_to_operand() began ignoring PlaceHolderVars.  
  
Author: Arne Roland <arne.roland@malkut.net>  
Reviewed-by: Tender Wang <tndrwang@gmail.com>  
Reviewed-by: Richard Guo <guofenglinux@gmail.com>  
Discussion: https://postgr.es/m/27a44087-3d65-473e-8d88-7c12228e0d7e@malkut.net  
Backpatch-through: 18  

M src/backend/optimizer/plan/analyzejoins.c
M src/test/regress/expected/join.out
M src/test/regress/sql/join.sql

Shorten pg_attribute_always_inline to pg_always_inline

commit   : d1d9688b1f92590110cb868ce4f65f39da0af2a8    
  
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    

Click here for diff

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/commands/copyfromparse.c
M src/backend/commands/copyto.c
M src/backend/executor/execExprInterp.c
M src/backend/executor/execTuples.c
M src/backend/executor/nodeHashjoin.c
M src/backend/nodes/queryjumblefuncs.c
M src/backend/storage/buffer/bufmgr.c
M src/backend/utils/adt/json.c
M src/backend/utils/cache/catcache.c
M src/include/c.h
M src/include/executor/execScan.h

libpq: Make error checks in the new buffer draining code more robust

commit   : 87c3a79ea206410f34f326eb63c36d8679edeb8b    
  
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    

Click here for diff

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   : 27761c0151b3b9b57e58597fa027a26619c9608e    
  
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    

Click here for diff

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

Fix RETURNING OLD with BEFORE UPDATE trigger and concurrent update.

commit   : 4908225bebdc31c9b8f735ad1db3d08d9bc85148    
  
author   : Dean Rasheed <dean.a.rasheed@gmail.com>    
date     : Wed, 8 Jul 2026 20:46:26 +0100    
  
committer: Dean Rasheed <dean.a.rasheed@gmail.com>    
date     : Wed, 8 Jul 2026 20:46:26 +0100    

Click here for diff

When executing an UPDATE with a RETURNING clause on a table with a  
BEFORE UPDATE row trigger, the computation of the OLD values in the  
RETURNING list was incorrect if the target tuple was concurrently  
updated by another session, at isolation level READ COMMITTED.  
  
The problem was that the trigger code would lock the target tuple,  
waiting for the other session to commit, and then fetch the updated  
target tuple, but ExecUpdate() would not realise that the target tuple  
had changed, and use the outdated target tuple for computing OLD  
values. Fix by having ExecUpdate() check the TM_FailureData from  
trigger execution and re-fetch the target tuple if necessary.  
  
Re-fetching the target tuple like this is a little inefficient, but  
probably negligible compared to the trigger execution and update. A  
better long-term fix might be to move the EPQ code out of trigger.c,  
and let ExecUpdate() handle it, like ExecMergeMatched() does, but that  
would likely mean changing the trigger API, which seems a bit much for  
back-patching.  
  
Backpatch to v18, where support for RETURNING OLD/NEW was added.  
  
Bug: #19536  
Reported-by: Jonas Boberg <bobergj@gmail.com>  
Diagnosed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>  
Author: Dean Rasheed <dean.a.rasheed@gmail.com>  
Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>  
Discussion: https://postgr.es/m/19536-73ce5847e6c0e7b1@postgresql.org  
Backpatch-through: 18  

M src/backend/executor/nodeModifyTable.c
M src/test/isolation/expected/eval-plan-qual-trigger.out
M src/test/isolation/expected/merge-match-recheck.out
M src/test/isolation/specs/eval-plan-qual-trigger.spec
M src/test/isolation/specs/merge-match-recheck.spec

doc: Clarify COPY FROM WHERE expression restrictions

commit   : abecdbc6af0192eb8fc017af5c7a3bb3d5da1ae3    
  
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    

Click here for diff

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   : 1383cbd03141316d98329341191d856c65d7c2c2    
  
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    

Click here for diff

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   : 45364e49688a2a845c6b43b182da3b5f3d10cff8    
  
author   : Richard Guo <rguo@postgresql.org>    
date     : Wed, 8 Jul 2026 08:46:43 +0900    
  
committer: Richard Guo <rguo@postgresql.org>    
date     : Wed, 8 Jul 2026 08:46:43 +0900    

Click here for diff

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

pg_unicode_fast: fix final sigma logic.

commit   : 66ec24276b18d111b916e6189b25e5c0a998a1f2    
  
author   : Jeff Davis <jdavis@postgresql.org>    
date     : Tue, 7 Jul 2026 15:04:31 -0700    
  
committer: Jeff Davis <jdavis@postgresql.org>    
date     : Tue, 7 Jul 2026 15:04:31 -0700    

Click here for diff

If the string is preceded only by Case Ignorable characters, don't  
consider it to be a final sigma.  
  
In the process, refactor so that the preceding and following  
characters are found first, and then the rule is applied, to improve  
clarity.  
  
Discussion: https://postgr.es/m/c355354e6c3f4a7aafb047361b73db247260fca0.camel@j-davis.com  
Backpatch-through: 18  

M src/common/unicode_case.c
M src/test/regress/expected/collate.utf8.out
M src/test/regress/sql/collate.utf8.sql

unicode_case.c: defend against truncated UTF8.

commit   : 9021c8f3cabc42839329e3ab0dfed4137557d19f    
  
author   : Jeff Davis <jdavis@postgresql.org>    
date     : Tue, 7 Jul 2026 13:35:15 -0700    
  
committer: Jeff Davis <jdavis@postgresql.org>    
date     : Tue, 7 Jul 2026 13:35:15 -0700    

Click here for diff

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/pg_locale_builtin.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   : bb0a54518176cfb513a9df4a9cf69ba189701fe6    
  
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    

Click here for diff

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   : 2167302b748fb8fa9112710014b50910b19b9f15    
  
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    

Click here for diff

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   : 50313f8f015efd8d4f2de89e4d7fa83a8205aa6d    
  
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    

Click here for diff

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   : cf184ec77a04bf164692a0c7bcd148f1e96b71f2    
  
author   : David Rowley <drowley@postgresql.org>    
date     : Tue, 7 Jul 2026 23:59:08 +1200    
  
committer: David Rowley <drowley@postgresql.org>    
date     : Tue, 7 Jul 2026 23:59:08 +1200    

Click here for diff

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   : 441e4c8d699910ea21f7f31ae7e76dbc1e572e05    
  
author   : Amit Langote <amitlan@postgresql.org>    
date     : Tue, 7 Jul 2026 08:13:42 +0900    
  
committer: Amit Langote <amitlan@postgresql.org>    
date     : Tue, 7 Jul 2026 08:13:42 +0900    

Click here for diff

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

Fix mishandling of leading '\' in nondeterministic LIKE.

commit   : 51652c42da2e982fb7028970eea5eed4c670a555    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 6 Jul 2026 14:47:58 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 6 Jul 2026 14:47:58 -0400    

Click here for diff

The loop in MatchText() processed a leading '\' without regard to  
nondeterministic locales, which is problematic if what the '\'  
precedes is an ordinary character that should be subject to  
nondeterministic matching.  We'd insist on a literal match for it,  
which is not right and is not like what happens with a '\' that  
follows some ordinary characters.  Worse, we'd then advance the text  
and pattern pointers by one byte, so that if the escaped character  
is multibyte the next loop iteration would take the nondeterministic  
code path starting at a point within the character.  That could very  
possibly cause pg_strncoll() to misbehave.  
  
The fix is quite simple: move the stanza that handles '\' down past  
the one that handles nondeterminism.  The stanzas for '%' and '_'  
are fine where they are, but the '\' stanza is only correct for  
deterministic matching.  The logic for nondeterministic cases is  
already prepared to do the right things with a '\'.  
  
While here, I replaced tests of "locale && !locale->deterministic"  
with a boolean local variable, reasoning that those are in the hot  
loop paths so saving a branch and indirect fetch is worth the  
trouble.  I also improved a number of related comments.  
  
Author: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/391592.1783187986@sss.pgh.pa.us  
Backpatch-through: 18  

M src/backend/utils/adt/like_match.c
M src/test/regress/expected/collate.icu.utf8.out
M src/test/regress/sql/collate.icu.utf8.sql

Fix LIKE matching with nondeterministic collations and backslashes.

commit   : a99bd8d584ea268d8a3d02d0f0facb74429ffcf9    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 6 Jul 2026 14:35:21 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 6 Jul 2026 14:35:21 -0400    

Click here for diff

Commit 85b7efa1c added support for LIKE with nondeterministic  
collations, but it included a bug in the de-escaping logic for  
literal pattern substrings.  That unconditionally skipped all  
backslashes, but when it encounters '\\' it should emit the second  
backslash as a de-escaped character.  That led to acting as though  
the escaped backslash was not there.  
  
Bug: #19474  
Reported-by: Bowen Shi <zxwsbg12138@gmail.com>  
Author: Nitin Motiani <nitinmotiani@google.com>  
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>  
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>  
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/19474-5b86a95f3d9a7ecb@postgresql.org  
Discussion: https://postgr.es/m/CAH5HC94yU+K8Gcdy12M5BS8gwD_SXLSHzc9k5tNk7JDnpBiFMA@mail.gmail.com  
Backpatch-through: 18  

M src/backend/utils/adt/like_match.c
M src/test/regress/expected/collate.icu.utf8.out
M src/test/regress/sql/collate.icu.utf8.sql

Fix LIKE/regex optimization for indexscan with exact-match pattern.

commit   : d0bb49e61168953f0f07c3beeb2b8fb63a3521a2    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 6 Jul 2026 13:06:21 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Mon, 6 Jul 2026 13:06:21 -0400    

Click here for diff

Commit 85b7efa1c introduced support for LIKE with non-deterministic  
collations.  By moving some conditionals around, it accidentally broke  
the optimization for converting a LIKE or regex exact-match pattern  
to an equality indexqual when the index collation doesn't match the  
expression collation.  That should be allowed if the expression  
collation is deterministic.  This patch re-introduces the optimization  
for that common case.  
  
One important beneficiary of this optimization is the "\d tablename"  
command in psql.  Without this fix that will do a seqscan on pg_class  
instead of an index point lookup.  
  
Reported-by: Andres Freund <andres@anarazel.de>  
Author: Jelte Fennema-Nio <postgres@jeltef.nl>  
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/DHBQIZX8SZVI.ZX614ZMFL645@jeltef.nl  
Backpatch-through: 18  

M src/backend/utils/adt/like_support.c
M src/test/regress/expected/collate.icu.utf8.out
M src/test/regress/expected/collate.out
M src/test/regress/sql/collate.icu.utf8.sql
M src/test/regress/sql/collate.sql

Prevent satisfies_hash_partition from crashing with VARIADIC NULL.

commit   : 0c06ebf126a0d5df39d9c4298193d9887443ce93    
  
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    

Click here for diff

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

Fix qual pushdown past grouping with mismatched equivalence

commit   : fe5d62951b3ccd382a530b790c3c2cb508b97c8c    
  
author   : Richard Guo <rguo@postgresql.org>    
date     : Mon, 6 Jul 2026 16:15:45 +0900    
  
committer: Richard Guo <rguo@postgresql.org>    
date     : Mon, 6 Jul 2026 16:15:45 +0900    

Click here for diff

The planner has two optimizations that move a qual clause across a  
grouping boundary: subquery_planner transfers HAVING clauses to WHERE  
so they can be evaluated before aggregation, and qual_is_pushdown_safe  
pushes outer restriction clauses into a subquery past its DISTINCT,  
DISTINCT ON, window PARTITION BY, or set-operation grouping layer.  
Both produce wrong results when the moved clause's equivalence  
relation disagrees with the grouping's, since the clause then filters  
rows the grouping would have merged.  
  
The disagreement has two forms.  A type may belong to multiple btree  
opfamilies whose equality operators disagree (e.g. record_ops vs  
record_image_ops); or the grouping may use a nondeterministic  
collation, where comparing the column under a different collation, or  
wrapping it in a function or operator, can distinguish values the  
collation considers equal.  Because we cannot prove an arbitrary  
expression preserves that equality, a grouping column with a  
nondeterministic collation is safe to push only as a direct operand of  
a comparison under its own collation.  
  
Fix both call sites through a shared walker parameterized by a  
callback that maps each Var to the grouping equality operator for its  
column (or InvalidOid for non-grouping Vars).  For HAVING, the  
callback recovers the SortGroupClause's eqop via the GROUP Var's  
varattno, which requires running before flatten_group_exprs while  
havingQual still contains GROUP Vars.  For subquery pushdown, the  
callback recovers the eqop from subquery->distinctClause, a window's  
partitionClause, or any grouping node in the SetOperationStmt tree.  
The walker fires only when there is an equivalence boundary to cross,  
gated by either the existing UNSAFE_NOTIN_DISTINCTON_CLAUSE and  
UNSAFE_NOTIN_PARTITIONBY_CLAUSE flags or by a recursive check for any  
grouping node in the set-op tree.  
  
Back-patch to v18 only.  The HAVING half relies on the RTE_GROUP  
mechanism introduced in v18 (commit 247dea89f), which is what lets us  
identify grouping expressions via GROUP Vars on pre-flatten  
havingQual.  Pre-v18 branches lack that machinery, so a back-patch  
there would need a different approach.  Given the absence of field  
reports of these bugs on back branches, the risk of carrying a  
different fix on stable branches is not justified.  
  
Author: Richard Guo <guofenglinux@gmail.com>  
Reviewed-by: Thom Brown <thom@linux.com>  
Reviewed-by: Florin Irion <irionr@gmail.com>  
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>  
Reviewed-by: Tender Wang <tndrwang@gmail.com>  
Reviewed-by: Chengpeng Yan <chengpeng_yan@outlook.com>  
Discussion: https://postgr.es/m/CAMbWs4-QLZpn3UVOpeG2fOxxhdnkDNMZ_3Zcm3dqJwRAphz68g@mail.gmail.com  
Backpatch-through: 18  

M src/backend/optimizer/path/allpaths.c
M src/backend/optimizer/plan/planner.c
M src/backend/optimizer/util/clauses.c
M src/backend/utils/cache/lsyscache.c
M src/include/optimizer/clauses.h
M src/include/utils/lsyscache.h
M src/test/regress/expected/aggregates.out
M src/test/regress/expected/collate.icu.utf8.out
M src/test/regress/expected/subselect.out
M src/test/regress/sql/aggregates.sql
M src/test/regress/sql/collate.icu.utf8.sql
M src/test/regress/sql/subselect.sql
M src/tools/pgindent/typedefs.list

Restore basebackup_progress_done() to preserve ABI

commit   : e2ad214dd80adbe905253b5689db4bf6e0ce7788    
  
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    

Click here for diff

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

amcheck: Fix memory leak with gin_index_check()

commit   : 1f8ab91c11ebf3d6521e2c9d67e321b1256f364c    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 6 Jul 2026 09:32:30 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Mon, 6 Jul 2026 09:32:30 +0900    

Click here for diff

"prev_tuple" was overwritten with a new tuple coming from  
CopyIndexTuple() on each loop, leaking memory for every tuple processed  
on entry tree pages.  The function uses a dedicated memory context, but  
this could leave unused large areas of memory while processing a large  
GIN index, the larger the worse.  
  
Oversight in 14ffaece0fb5.  
  
Author: Kirill Reshke <reshkekirill@gmail.com>  
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>  
Discussion: https://postgr.es/m/CALdSSPjTS6TYe5=5NfMUBYZyQu5cn=ABL6K5_OZjzGWqnwXeBw@mail.gmail.com  
Backpatch-through: 18  

M contrib/amcheck/verify_gin.c

Disallow renaming a rule to "_RETURN".

commit   : a7f7958ab6bf368236334ce52e45be5e7502d2e7    
  
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    

Click here for diff

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   : 12c519207db01a9d4a6b47b205883928a083758f    
  
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    

Click here for diff

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

Use the proper comparator in gbt_bit_ssup_cmp.

commit   : 558c4ea9a43b27d4ddb702fc455cf641d3792cde    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Fri, 3 Jul 2026 13:11:14 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Fri, 3 Jul 2026 13:11:14 -0400    

Click here for diff

If we're dealing with leaf entries, the function to call is bitcmp  
not byteacmp.  Using byteacmp didn't lead to any obvious failure,  
but it did result in sorting the entries in a way not matching the  
datatype's actual sort order.  Hence the constructed index would be  
less efficient than one would expect, and in particular worse than  
what you got before this code was added in v18 (by commit e4309f73f).  
  
We might want to recommend that users reindex btree_gist indexes  
on bit/varbit columns.  
  
Author: Tom Lane <tgl@sss.pgh.pa.us>  
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>  
Discussion: https://postgr.es/m/AH*AvQCYKhQGVvPWi1GiU4oY.8.1781609375063.Hmail.3020001251@tju.edu.cn  
Backpatch-through: 18  

M contrib/btree_gist/btree_bit.c

Prevent access to other sessions' empty temp tables

commit   : 3aaefe8924f4828eabd414bfda98793e769aed8e    
  
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    

Click here for diff

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

Fix tracing of BackendKeyData and CancelRequest

commit   : dd5eca055d484af41eb6d50d6eeea7cb065d450c    
  
author   : Heikki Linnakangas <heikki.linnakangas@iki.fi>    
date     : Fri, 3 Jul 2026 14:57:35 +0300    
  
committer: Heikki Linnakangas <heikki.linnakangas@iki.fi>    
date     : Fri, 3 Jul 2026 14:57:35 +0300    

Click here for diff

BackendKeyData length was increased from 4 bytes to a variable-length  
length (up to 256 bytes) in a460251f0a. However, pqTrace still traces  
it as a 4 bytes key, leading to a "mismatched message length" warning  
message. The same issue impacts the tracing of CancelRequest.  
  
This patch fixes the issue by using pqTraceOutputNchar instead of  
pqTraceOutputInt32 in both cases.  
  
Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>  
Discussion: https://www.postgresql.org/message-id/CAO6_Xqo6gTv9=76H=k2qDRFU+KHuBiY2S=bQynEr6J8gS7L6xA@mail.gmail.com  
Backpatch-through: 18  

M src/interfaces/libpq/fe-trace.c

psql: Fix \df tab completion for procedures

commit   : 598af79b1b5e1b62c5409a8e6f7b3126848d17c8    
  
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    

Click here for diff

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.in.c

Remove replication slot advice from MultiXact wraparound hints

commit   : c8d68bfd52d70d7b416c0eb775df29634c583fef    
  
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    

Click here for diff

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   : 90789900b84a71d9c21d46220dd2e2a2477d3322    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Thu, 2 Jul 2026 15:06:05 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Thu, 2 Jul 2026 15:06:05 +0900    

Click here for diff

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   : 84001a04d552ffd00863a3a9f67f42fc8cb0b677    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Thu, 2 Jul 2026 12:44:33 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Thu, 2 Jul 2026 12:44:33 +0900    

Click here for diff

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   : 1e1d07792e0827ca84685784c0c958127f5853eb    
  
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    

Click here for diff

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   : e7564ee8cdcbdc7e8ed06b31bbcd0f80d6e81cd3    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Wed, 1 Jul 2026 23:03:08 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Wed, 1 Jul 2026 23:03:08 +0900    

Click here for diff

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   : 215ab56119e02ec77b3bd417ccf5334f9259bb52    
  
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    

Click here for diff

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   : 6a6cf80e5508c8de3e46b257e18117373ebbd289    
  
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    

Click here for diff

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   : 627605713074e51f29b623cd799e37a9f411c57b    
  
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    

Click here for diff

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   : d36b728949bf4e37ada1cd23e0f2aaa94f609a70    
  
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    

Click here for diff

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   : 53482fcb94a82cc22e20a7206c508a39aa07a76d    
  
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    

Click here for diff

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

Avoid collation lookup failure when considering a "char" column.

commit   : 5fd1c3f287189cfa4bff4ac3492c313417dff7c9    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Sun, 28 Jun 2026 12:31:29 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Sun, 28 Jun 2026 12:31:29 -0400    

Click here for diff

If a "char" column has a statistics histogram, scalarineqsel()  
would fail with "cache lookup failed for collation 0".  Avoid  
the failing lookup by acting as though the collation is "C".  
  
Prior to commit 06421b084, this code didn't fail because  
lc_collate_is_c() intentionally didn't spit up on InvalidOid.  
It did act differently though: it would take the non-C-collation  
code path and hence apply strxfrm using libc's prevailing locale.  
But that seems like the wrong thing for a non-collatable comparison,  
so let's not resurrect that aspect.  
  
Author: Feng Wu <wufengwufengwufeng@gmail.com>  
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/CACK3muq6s-O1Wc3w4dRL1Fe8YQ-Fz1zJbezeQwhuLgNxGNEFiA@mail.gmail.com  
Backpatch-through: 18  

M src/backend/utils/adt/selfuncs.c

Fix out-of-bounds access in autoprewarm worker

commit   : 3bf2cb22576eac50d80e3eecd485fcae4fdd7f8b    
  
author   : Tomas Vondra <tomas.vondra@postgresql.org>    
date     : Fri, 26 Jun 2026 19:34:14 +0200    
  
committer: Tomas Vondra <tomas.vondra@postgresql.org>    
date     : Fri, 26 Jun 2026 19:34:14 +0200    

Click here for diff

The read stream callback apw_read_stream_next_block() advances p->pos  
through the block_info array. When processing the last block, it  
increments p->pos to prewarm_stop_idx before returning. The callback  
itself is safe because it checks bounds before accessing the array.  
  
However, the caller assigned blk from block_info[i] at the end of the  
loop body, before the loop condition was re-evaluated. When i equaled  
prewarm_stop_idx, this accessed memory beyond the allocated DSM segment,  
causing a segfault.  
  
Restructure the loop to check bounds at the top and assign blk at the  
beginning of the loop body, where it is always safe. This avoids the  
need for an explicit bounds check at the end.  
  
Backpatch to 18, where the bug was introduced by commit 6acab8bdbcda.  
  
Author: Matheus Alcantara <mths.dev@pm.me>  
Reported-by: Glauber Batista <glauberrbatista@gmail.com>  
Reviewed-by: Melanie Plageman <melanieplageman@gmail.com>  
Reviewed-by: Tomas Vondra <tomas@vondra.me>  
Backpatch-through: 18  
Discussion: https://www.postgresql.org/message-id/CAO%2B_mTQgQyTYwDh%3DU8iTnsDmOGyWsZJjUV31SmEYwmw6_xY6Bw%40mail.gmail.com  

M contrib/pg_prewarm/autoprewarm.c

Fix null-pointer crash in ECPG compiler.

commit   : 917fdbc633e24e652427e102bf51484f3e1ab2f2    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Thu, 25 Jun 2026 16:58:29 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Thu, 25 Jun 2026 16:58:29 -0400    

Click here for diff

When compiling a DECLARE section containing a union nested  
inside a struct, ecpg passes a null value for struct_sizeof to  
ECPGmake_struct_type.  I (tgl) didn't foresee that case in  
commit 0e6060790, and wrote an unprotected mm_strdup() call.  
  
Reported-by: iMSA (via Jehan-Guillaume de Rorthais <jgdr@dalibo.com>)  
Author: Jehan-Guillaume de Rorthais <jgdr@dalibo.com>  
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/20260625114849.34b2148e@karst  
Backpatch-through: 18  

M src/interfaces/ecpg/preproc/type.c

Avoid ABI break in ModifyTableState from the FDW pruning fix

commit   : bba4e095d25005dd0b2f180187ff2c2adf48a3b3    
  
author   : Amit Langote <amitlan@postgresql.org>    
date     : Thu, 25 Jun 2026 12:12:59 +0900    
  
committer: Amit Langote <amitlan@postgresql.org>    
date     : Thu, 25 Jun 2026 12:12:59 +0900    

Click here for diff

Commit 1ef917e3a6 fixed the re-indexing of ModifyTable's FDW arrays  
when initial runtime pruning removes result relations, but it did so  
by adding a new mt_fdwPrivLists field to ModifyTableState.  Although  
the field was placed at the end of the struct to keep the offsets of  
existing fields stable, it still enlarges sizeof(ModifyTableState),  
which the ABI compliance check flags on the buildfarm (e.g. crake).  
  
The field existed only so that show_modifytable_info() could recover the  
re-indexed fdw_private after executor startup; the executor-side fix in  
ExecInitModifyTable() that actually prevents the crash does not depend on  
it.  Remove the field and have show_modifytable_info() instead look up  
each kept relation's fdw_private from the original, pre-pruning  
node->fdwPrivLists, which is parallel to node->resultRelations and left  
intact by pruning.  When nothing was pruned the lookup is a direct index;  
otherwise it matches on the range table index.  
  
This is applied to REL_18 only; master keeps the mt_fdwPrivLists field  
and is unaffected, so the two diverge slightly here.  
  
Reported on the buildfarm (member crake).  
  
Per a suggestion from Tom Lane.  
  
Reviewed-by: Etsuro Fujita <etsuro.fujita@gmail.com>  
Discussion: https://postgr.es/m/CA+HiwqEhe7-v5Q0-oOoW3RaO4voYcGK-JfinbYEWXwutDGSOtQ@mail.gmail.com  

M src/backend/commands/explain.c
M src/backend/executor/nodeModifyTable.c
M src/include/nodes/execnodes.h

plperl: Fix NULL pointer dereference for forged array object

commit   : e430ecc5958bb1ef95133f5b3c83dbb98ac255c8    
  
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    

Click here for diff

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

Re-index ModifyTable FDW arrays when pruning result relations

commit   : 1ef917e3a61a26a264fe65012d951ac36aa03732    
  
author   : Amit Langote <amitlan@postgresql.org>    
date     : Mon, 22 Jun 2026 17:21:45 +0900    
  
committer: Amit Langote <amitlan@postgresql.org>    
date     : Mon, 22 Jun 2026 17:21:45 +0900    

Click here for diff

ExecInitModifyTable() rebuilds the per-result-relation lists after  
dropping result relations removed by initial runtime pruning.  The  
re-indexing was done for withCheckOptionLists, returningLists,  
updateColnosLists, mergeActionLists and mergeJoinConditions, but  
fdwPrivLists and fdwDirectModifyPlans were missed.  As a result, a  
kept foreign result relation could be handed the wrong fdw_private,  
or ri_usesFdwDirectModify could be set from the wrong plan index,  
leading to wrong behavior or a crash in BeginForeignModify() and in  
the direct-modify path.  
  
show_modifytable_info() had the same problem: it indexed the  
plan-ordered node->fdwPrivLists with the post-pruning executor  
position, so once initial pruning removed a result relation it  
could read a different relation's fdw_private (often a NIL entry),  
producing wrong EXPLAIN output or a crash.  
  
Fix by re-indexing fdwPrivLists and fdwDirectModifyPlans alongside  
the other lists, saving the re-indexed private lists in  
ModifyTableState.mt_fdwPrivLists and reading from there in both  
nodeModifyTable.c and explain.c.  
  
Reported-by: Chi Zhang <798604270@qq.com>  
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>  
Author: Rafia Sabih <rafia.pghackers@gmail.com>  
Reviewed-by: Matheus Alcantara <matheusssilv97@gmail.com>  
Reviewed-by: Etsuro Fujita <etsuro.fujita@gmail.com>  
Discussion: https://postgr.es/m/19484-a3cb82c8cde3c8fa%40postgresql.org  
Backpatch-through: 18  

M contrib/postgres_fdw/expected/postgres_fdw.out
M contrib/postgres_fdw/sql/postgres_fdw.sql
M src/backend/commands/explain.c
M src/backend/executor/nodeModifyTable.c
M src/include/nodes/execnodes.h

doc: Describe better handling of indexes in ALTER TABLE ATTACH PARTITION

commit   : d3ff08e66b430215e1999c07e6f0c6573e6d39d9    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Tue, 23 Jun 2026 16:52:15 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Tue, 23 Jun 2026 16:52:15 +0900    

Click here for diff

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   : fe464e9e68633c471e8ecb83adb7151decdd437e    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Tue, 23 Jun 2026 07:58:04 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Tue, 23 Jun 2026 07:58:04 +0900    

Click here for diff

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.c
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
M src/test/modules/injection_points/injection_stats.c

Fix unsafe order of operations in ResourceOwnerReleaseAll().

commit   : ac6a58a700da1262d669e970f7ccba66f916c412    
  
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    

Click here for diff

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   : 020426268ff6acaa140780336eb1c50b034cb893    
  
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    

Click here for diff

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

Strip removed-relation references from PlaceHolderVars at join removal

commit   : e0252679559adaeee16a7924430f542a1cad3ab7    
  
author   : Richard Guo <rguo@postgresql.org>    
date     : Mon, 22 Jun 2026 10:43:01 +0900    
  
committer: Richard Guo <rguo@postgresql.org>    
date     : Mon, 22 Jun 2026 10:43:01 +0900    

Click here for diff

When left-join removal deletes a relation, remove_rel_from_query()  
updates the relid sets attached to RestrictInfos and  
EquivalenceMembers, and the canonical PlaceHolderVar held in each  
PlaceHolderInfo, but it does not rewrite the PlaceHolderVars embedded  
in clause and EquivalenceClass member expressions.  That has been  
fine, because later processing consults those relid sets rather than  
the embedded PlaceHolderVars.  
  
However, such an expression may afterwards be translated for an  
appendrel child and have its relids recomputed from scratch by  
pull_varnos().  If the embedded PlaceHolderVar's phrels still mentions  
the removed relation, pull_varnos() folds it back in, so the rebuilt  
clause's relids reference a no-longer-existent relation.  That yields  
a parameterized path keyed on the removed relation, tripping the  
Assert on root->outer_join_rels in get_eclass_indexes_for_relids().  
  
Fix by stripping the removed relids from the PlaceHolderVars in  
surviving rels' baserestrictinfo and in EquivalenceClass member  
expressions, keeping them consistent with the canonical  
PlaceHolderVars.  
  
This is only reachable on v18 and later, where  
match_index_to_operand() began ignoring PlaceHolderVars; before that,  
the wrapping PlaceHolderVar prevented the index match that exposes the  
stale relids.  
  
Reported-by: Alexander Kuzmenkov <akuzmenkov@tigerdata.com>  
Author: Richard Guo <guofenglinux@gmail.com>  
Reviewed-by: Tender Wang <tndrwang@gmail.com>  
Discussion: https://postgr.es/m/CALzhyqwryL2QywgO03VQr_237Sq3MEVgTTT2_A9G3nGT5-SRZg@mail.gmail.com  
Backpatch-through: 18  

M src/backend/optimizer/plan/analyzejoins.c
M src/test/regress/expected/join.out
M src/test/regress/sql/join.sql

Make pg_mkdir_p() tolerant of a concurrent directory creation.

commit   : aa80c34c85f4eb81d515f341b663bd196d18837c    
  
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    

Click here for diff

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

Update JIT tuple deforming code for virtual generated columns

commit   : e9692de1d6f617031be73251949eae31b29275bd    
  
author   : David Rowley <drowley@postgresql.org>    
date     : Fri, 19 Jun 2026 15:26:51 +1200    
  
committer: David Rowley <drowley@postgresql.org>    
date     : Fri, 19 Jun 2026 15:26:51 +1200    

Click here for diff

The JIT deforming code contains an optimization that determines which  
columns are guaranteed to exist in the tuple.  That's used to allow  
skipping of reading the tuple's natts when the code only needs to deform  
attributes that are guaranteed to always exist in all tuples.  83ea6c540  
missed updating this code to account for VIRTUAL generated columns.  
These are stored as NULLs in the tuple, but may be defined as NOT NULL.  
This could result in the code thinking more columns are guaranteed to  
exist than actually do.  
  
Author: David Rowley <dgrowleyml@gmail.com>  
Reviewed-by: Chao Li <li.evan.chao@gmail.com>  
Backpatch-through: 18  
Discussion: https://postgr.es/m/1151393.1781734980@sss.pgh.pa.us  

M src/backend/jit/llvm/llvmjit_deform.c
M src/test/regress/expected/generated_virtual.out
M src/test/regress/sql/generated_virtual.sql

Silence "may be used uninitialized" compiler warning.

commit   : 78d89a7b531623855318b85421004b1aeccccff0    
  
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    

Click here for diff

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   : d65cf6f800f00a560cd479b426a17f73dd0020f7    
  
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    

Click here for diff

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

commit   : 5562b2657f942113b77bd557234a2ac4d08a49c5    
  
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    

Click here for diff

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   : 8a4f389ddce54c5b9bc1f0dcc99e9f74944be813    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Thu, 18 Jun 2026 14:48:37 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Thu, 18 Jun 2026 14:48:37 +0900    

Click here for diff

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   : 08458bcaea5bc893c6150cc86adbac259a5d7b36    
  
author   : Amit Kapila <akapila@postgresql.org>    
date     : Thu, 18 Jun 2026 09:42:56 +0530    
  
committer: Amit Kapila <akapila@postgresql.org>    
date     : Thu, 18 Jun 2026 09:42:56 +0530    

Click here for diff

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   : 5cc59834b860ed48d710c1baa9c50c66540c64d0    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Thu, 18 Jun 2026 11:49:34 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Thu, 18 Jun 2026 11:49:34 +0900    

Click here for diff

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.c
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
M src/test/modules/injection_points/injection_stats.c

oauth: Skip call-count test for libcurl 8.20.0

commit   : c5c35fd7c55cfc3ad072d131bff7472dd49a97b2    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Wed, 17 Jun 2026 09:57:59 -0700    
  
committer: Jacob Champion <jchampion@postgresql.org>    
date     : Wed, 17 Jun 2026 09:57:59 -0700    

Click here for diff

The call-count test in 001_server.pl runs into a recent upstream  
regression in Curl:  
  
    https://github.com/curl/curl/issues/21547  
  
The symptom is high CPU usage on some platforms during OAuth HTTP  
requests. But it looks like the fix is on track for a June 2026 release,  
as part of Curl 8.21.0, so just skip the test if we happen to be using  
the broken version.  
  
Reported-by: Andrew Dunstan <andrew@dunslane.net>  
Reported-by: Tom Lane <tgl@sss.pgh.pa.us>  
Tested-by: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/CAOYmi%2B%3DyrwMSsHuNJ1V14isA4iSix5Xb3P3VEp1X0BS61MdV4A%40mail.gmail.com  
Backpatch-through: 18  

M src/test/modules/oauth_validator/t/001_server.pl

libpq-oauth: Print libcurl version with OAUTHDEBUG_UNSAFE_TRACE

commit   : 357e4d64f871cccd57390581070c4239465c2eb5    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Wed, 17 Jun 2026 09:57:20 -0700    
  
committer: Jacob Champion <jchampion@postgresql.org>    
date     : Wed, 17 Jun 2026 09:57:20 -0700    

Click here for diff

When debugging an OAuth trace, it's helpful to know what version of Curl  
is in use. The SSL library that Curl is using (which may not be the one  
in use by libpq) is also relevant, and it's just as easy to get, so  
print that too.  
  
This is being added post-feature-freeze, with RMT approval, in order to  
fix some tests in the face of an upstream Curl regression. A subsequent  
commit will make use of it in oauth_validator. Backpatch to 18 as well.  
  
Tested-by: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/CAOYmi%2B%3DkP86t%2BZFFXNQ9G6K4ht7utdmB%3DCzhP%3DZ2wvuBymOTtQ%40mail.gmail.com  
Backpatch-through: 18  

M src/interfaces/libpq-oauth/oauth-curl.c

oauth_validator: Print captured stderr after call-count failure

commit   : 1fb397f730b209edaff995f9cc411a5d8ed2d65f    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Wed, 17 Jun 2026 09:57:15 -0700    
  
committer: Jacob Champion <jchampion@postgresql.org>    
date     : Wed, 17 Jun 2026 09:57:15 -0700    

Click here for diff

If the call count test fails, you'll reasonably want to know what the  
network trace looked like, but that information is currently swallowed.  
Print it out instead.  
  
Backpatch-through: 18  

M src/test/modules/oauth_validator/t/001_server.pl

jsonb_plperl, jsonb_plpython: Fix unguarded recursion and loops.

commit   : e3b7a43fa9b6f7f5d33584080276bea66606b644    
  
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    

Click here for diff

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

vacuumdb: Fix --missing-stats-only for partitioned indexes.

commit   : 7e085aabd5759c73d25556a5963866d5beaea5cd    
  
author   : Nathan Bossart <nathan@postgresql.org>    
date     : Wed, 17 Jun 2026 09:18:39 -0500    
  
committer: Nathan Bossart <nathan@postgresql.org>    
date     : Wed, 17 Jun 2026 09:18:39 -0500    

Click here for diff

The current form of the catalog query picks up partitioned tables  
with expression indexes that lack statistics.  However, since such  
indexes never have statistics, there's no point in analyzing them.  
To fix, adjust the relevant part of the query to skip partitioned  
tables with expression indexes.  While at it, remove the nearby  
stainherit check; entries for index expressions always have  
stainherit = false.  
  
Author: Baji Shaik <baji.pgdev@gmail.com>  
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>  
Discussion: https://postgr.es/m/CA%2Bfm-RPE1tEc6CUUPDyRbYTz9tF5Kw47nnk-Zq%3DyYvanbsxyCQ%40mail.gmail.com  
Backpatch-through: 18  

M src/bin/scripts/t/100_vacuumdb.pl
M src/bin/scripts/vacuumdb.c

Fix pgstat_count_io_op_time() calls passing incorrect information

commit   : 13f940b4b56f38414a0dbd820f65c8e74f55d466    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 17 Jun 2026 16:05:37 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 17 Jun 2026 16:05:37 +0900    

Click here for diff

Several calls of pgstat_count_io_op_time() have been used as data to  
count negative values returned by pg_pread() or pg_pwrite(), leading to  
an incorrect count reported, casting them back to uint64.  
  
Most of the problematic calls updated here are adjusted so as we do not  
report buggy negative numbers anymore.  In xlogrecovery.c, the spot  
updated still counts short reads.  In xlog.c, after a WAL segment  
initialization, I/O numbers are aggregated only after checking that the  
operation has succeeded.  
  
issues introduced by a051e71e28a1.  
  
Reported-by: Peter Eisentraut <peter@eisentraut.org>  
Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>  
Reviewed-by: Michael Paquier <michael@paquier.xyz>  
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>  
Discussion: https://postgr.es/m/0db864e6-4477-4eba-b2be-d3523cc86564@eisentraut.org  
Backpatch-through: 18  

M src/backend/access/transam/xlog.c
M src/backend/access/transam/xlogreader.c
M src/backend/access/transam/xlogrecovery.c
M src/backend/replication/walreceiver.c

Fix another instability in recovery TAP test 004_timeline_switch

commit   : 5a4fea0ce5d994479c8cdd0716816b3ae67a2070    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 17 Jun 2026 08:42:08 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 17 Jun 2026 08:42:08 +0900    

Click here for diff

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   : bd7b2184390fb7ce4a37709a199990e55b251698    
  
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    

Click here for diff

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

pg_restore: Use dependency-based matching for STATISTICS DATA

commit   : 477efef089c31f7d260c923d64a2a75cb3aa580a    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Tue, 16 Jun 2026 15:58:17 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Tue, 16 Jun 2026 15:58:17 +0900    

Click here for diff

The previous approach introduced by 0dd93de69e80 was weak in terms of  
name matching, as an --index=foo could match with a table with the same  
name but from a different schema, pulling in more data than necessary.  
  
For example, imagine the following case:  
CREATE SCHEMA s1;  
CREATE SCHEMA s2;  
CREATE TABLE s1.foo (id int);  
INSERT INTO s1.foo SELECT generate_series(1,100);  
ANALYZE s1.foo;  
CREATE TABLE s2.bar (id int);  
CREATE INDEX foo ON s2.bar(id);  
INSERT INTO s2.bar SELECT generate_series(1,100);  
ANALYZE s2.bar;  
  
A targetted pg_restore --index=foo would grab the relation and attribute  
stats of s1.foo on top of the index s2.foo, which is incorrect.  This  
commit fixes this scenario by relying on a lookup of the dependencies of  
a STATISTICS DATA TOC entry, checking if a TOC entry depends on an index  
or another relkind before matching with the names of the objects wanted  
for the restore.  
  
Discussion: https://postgr.es/m/ajDBwpxs-otl585H@paquier.xyz  
Backpatch-through: 18  

M src/bin/pg_dump/pg_backup_archiver.c

Fix int32 overflow in ltree_compare()

commit   : c3e36a9a5f19bb7c2df07bc70d799a8bca682d8b    
  
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    

Click here for diff

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

pg_dump: Remove dead code in TAP tests

commit   : 54ffa74c9924a14691bb4cb196cb49e43a9fbd76    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Tue, 16 Jun 2026 08:31:43 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Tue, 16 Jun 2026 08:31:43 +0900    

Click here for diff

The schema_only_with_statistics test scenario was referenced in  
002_pg_dump.pl, but was associated to no command sequence since  
0ed92cf50cc4.  
  
Issue discovered while investigating a different bug.  Perhaps this  
cleanup is not worth backpatching, but there is also an argument in  
favor of reducing noise when touching this area of the code in stable  
branches.  
  
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>  
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>  
Discussion: https://postgr.es/m/ai-y0S7Z25NlrG_n@paquier.xyz  
Backpatch-through: 18  

M src/bin/pg_dump/t/002_pg_dump.pl

Fix inconsistencies with pg_restore --statistics[-only]

commit   : 42ffdedcf743c23ba346eba8e3afce9da5e8f618    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Tue, 16 Jun 2026 08:22:41 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Tue, 16 Jun 2026 08:22:41 +0900    

Click here for diff

Attempting to restore a schema, a table or an index with  
--only-statistics skipped all the statistics of the objects wanted.  
Like for pg_dump, statistics should be included, so this created an  
assymetry between dump and restore.  
  
A second set of problems existed for --table and --index, where the  
presence of --statistics skipped the restore of the stats of the  
object(s) targetted.  
  
This issue has been reported originally as related to an inconsistency  
with the way extended stats restore is handled in Postgres v19, but the  
issue is related to the restore of relation and attribute statistics in  
v18.  Some TAP tests are added to cover all these cases.  
  
Reported-by: Chao Li <li.evan.chao@gmail.com>  
Author: Chao Li <li.evan.chao@gmail.com>  
Author: Michael Paquier <michael@paquier.xyz>  
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>  
Discussion: https://postgr.es/m/66E80CAB-527C-42B1-BB65-3F82CF4AD998@gmail.com  
Backpatch-through: 18  

M src/bin/pg_dump/pg_backup_archiver.c
M src/bin/pg_dump/t/002_pg_dump.pl

Clean up quoting of variable strings within replication commands.

commit   : abb5825550a8b4a29e1ad7447a5165f4ec1357c7    
  
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    

Click here for diff

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   : 85e6624c06a187cb53ab8edc4dab1c47de6f898d    
  
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    

Click here for diff

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   : 6603e81e69e9b7378e2581f436119a7c6cb94cf9    
  
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    

Click here for diff

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   : b1ab4bc52a1fd4f8bf396baf4c1ab0a4c32f9b49    
  
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    

Click here for diff

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   : e592535d224f7dd411018e373104ffeb85fcddca    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 15 Jun 2026 11:37:55 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Mon, 15 Jun 2026 11:37:55 +0900    

Click here for diff

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   : b4db796b192cdbe6a78c8e3ef3d235c236e09528    
  
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    

Click here for diff

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   : 897e79486296d136855734a34de062eadfe3199b    
  
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    

Click here for diff

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   : 10e510423dc3a0e3c696b981b4d12096c5ab6428    
  
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    

Click here for diff

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   : 27cf3b5aff4fdb53d00f44760ecdce06ddb02925    
  
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    

Click here for diff

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   : 0d145be2c371a710cd85a5255ae843ee89393076    
  
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    

Click here for diff

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   : 4bff3aa51c194e31044da8177f91eecb0b30205b    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Fri, 12 Jun 2026 11:44:14 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Fri, 12 Jun 2026 11:44:14 +0900    

Click here for diff

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
M src/test/recovery/t/035_standby_logical_decoding.pl

doc: fix reference for finding replication slots to drop

commit   : 556324c386287f5fdd3f6a7848511b46c8fda597    
  
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    

Click here for diff

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   : 4c777d6dd9c9ac8fc8316329745ed1177989379d    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Fri, 12 Jun 2026 10:25:49 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Fri, 12 Jun 2026 10:25:49 +0900    

Click here for diff

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

amcheck: Fix missing allequalimage corruption report

commit   : 12c32bbc8582727ceb2776c72fa7b5a5f16d8d8c    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Fri, 12 Jun 2026 09:35:27 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Fri, 12 Jun 2026 09:35:27 +0900    

Click here for diff

When amcheck validates that a B-Tree metapage's allequalimage flag  
matches _bt_allequalimage(), it could fail to report corruption  
unless one of the index key columns used interval_ops. As a result,  
pg_amcheck could silently miss this corruption on other opclasses,  
incorrectly reporting the index as valid.  
  
The mistake was that bt_index_check_callback() kept ereport(ERROR)  
inside the loop that scans key attributes for INTERVAL_BTREE_FAM_OID,  
even though that loop is only needed to decide whether to add  
the interval-specific hint. This commit moves ereport() out of the loop  
so allequalimage mismatches are always reported, while still emitting  
the hint for affected interval indexes.  
  
Back-patch to v18, where d70b17636dd introduced this regression  
while moving the check into bt_index_check_callback().  
  
Author: Chao Li <lic@highgo.com>  
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>  
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/011ACC9C-CB87-4160-ACE7-4ED57AB86E15@gmail.com  
Backpatch-through: 18  

M contrib/amcheck/verify_nbtree.c

IS JSON/JSON(): Protect against expressions uncoercible to text

commit   : 35d9a6263407563f9948a38fced5419deab297a2    
  
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    

Click here for diff

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

Fix parsing of parenthesised OLD/NEW in RETURNING list.

commit   : 9108fed3eda97475d5ef2f9060f6bc1f61783346    
  
author   : Dean Rasheed <dean.a.rasheed@gmail.com>    
date     : Thu, 11 Jun 2026 12:08:48 +0100    
  
committer: Dean Rasheed <dean.a.rasheed@gmail.com>    
date     : Thu, 11 Jun 2026 12:08:48 +0100    

Click here for diff

When parsing expressions like (old).colname and (old).* in a RETURNING  
list, the parser would lose track of the intended varreturningtype,  
and therefore return incorrect results.  
  
The root cause was code using GetNSItemByRangeTablePosn() to find a  
namespace item from its rtindex and levelsup, without taking into  
account returningtype, which would return the wrong namespace item.  
Fix by adding a new function GetNSItemByVar() that does take  
returningtype into account.  
  
Backpatch to v18, where support for RETURNING OLD/NEW was added.  
  
Bug: #19516  
Reported-by: Marko Grujic <markoog@gmail.com>  
Author: Marko Grujic <markoog@gmail.com>  
Suggested-by: Dean Rasheed <dean.a.rasheed@gmail.com>  
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>  
Discussion: https://postgr.es/m/CAOvwyF2cO_5mAt=w=y-dFnaG5UkZ+3H8nSDoKF_iuWZHsU2ARg@mail.gmail.com  
Backpatch-through: 18  

M src/backend/parser/parse_coerce.c
M src/backend/parser/parse_func.c
M src/backend/parser/parse_relation.c
M src/backend/parser/parse_target.c
M src/include/parser/parse_relation.h
M src/test/regress/expected/returning.out
M src/test/regress/sql/returning.sql

seg: Fix seg_out() to preserve the upper boundary's certainty indicator

commit   : 0004cab4dc60577779d97a8f1a175b6dd07dc223    
  
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    

Click here for diff

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   : b4bd1385043c4664a7b8894a811ba91a61c6e07f    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Thu, 11 Jun 2026 17:29:38 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Thu, 11 Jun 2026 17:29:38 +0900    

Click here for diff

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   : 91b57eadeb0f1f971aebfc3f9c9045477b0e0438    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Thu, 11 Jun 2026 14:29:22 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Thu, 11 Jun 2026 14:29:22 +0900    

Click here for diff

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   : beb09e9117353f985c9aad6d5c6761193737da74    
  
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    

Click here for diff

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   : 26bd362655bc16e2f86eedb87a7d7c37a1d553d3    
  
author   : Jeff Davis <jdavis@postgresql.org>    
date     : Mon, 8 Jun 2026 13:10:40 -0700    
  
committer: Jeff Davis <jdavis@postgresql.org>    
date     : Mon, 8 Jun 2026 13:10:40 -0700    

Click here for diff

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   : c090bef07d13c7d424c2d145ca12c1fea9b9face    
  
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    

Click here for diff

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   : 89e6484985280b259a2346b4b4805750cf6ac0ce    
  
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    

Click here for diff

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   : 11aed8d19cd71d2754ac10c71ec668280bd955f5    
  
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    

Click here for diff

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   : be176e0a6d38bf9007b2192a404f9661a5b5b10a    
  
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    

Click here for diff

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   : 081434b0f582f05ea397dd3490f61b7400851e16    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Mon, 8 Jun 2026 17:07:48 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Mon, 8 Jun 2026 17:07:48 +0900    

Click here for diff

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   : 4154a148206375e4af136558953e78dd2a5398ef    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 8 Jun 2026 15:29:19 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Mon, 8 Jun 2026 15:29:19 +0900    

Click here for diff

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   : 07a6c262beeec418526672ff62d7da301100c34d    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 8 Jun 2026 14:37:56 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Mon, 8 Jun 2026 14:37:56 +0900    

Click here for diff

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

pg_surgery: Fix off-by-one bug with heap offset

commit   : 2b09f8a9110a5de217fa59dfb3215686def7dc36    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Sat, 6 Jun 2026 08:16:40 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Sat, 6 Jun 2026 08:16:40 +0900    

Click here for diff

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

doc: Use groups instead of curves in TLS documentation

commit   : a5112c9b62da069c352e58428f54f7a75d971779    
  
author   : Daniel Gustafsson <dgustafsson@postgresql.org>    
date     : Fri, 5 Jun 2026 22:16:42 +0200    
  
committer: Daniel Gustafsson <dgustafsson@postgresql.org>    
date     : Fri, 5 Jun 2026 22:16:42 +0200    

Click here for diff

With TLS 1.3 the concept of curves was renamed to groups.  Update  
our wording to use groups instead of curves to make it clear what  
the underlying GUC can support.  
  
This was extracted from a slightly larger patch which also renamed  
variables to match the new terminology.  Given that we are in beta  
this portion was however left as a future excercise.  
  
Author: Evan Si <evsi@amazon.com>  
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>  
Discussion: https://postgr.es/m/23C40DD6-1C47-46FC-A746-8A1D8530AD3E@amazon.com  
Backpatch-through: 18  

M doc/src/sgml/config.sgml

refint: Remove plan cache.

commit   : 79a506228bef41339ba64d27a47e7756dc1fd8db    
  
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    

Click here for diff

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

Fix off-by-one with NFC recomposition for Hangul U+11A7 (TBASE)

commit   : 273fe94852b3a7e34fd171e8abdf1481beb302fa    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Fri, 5 Jun 2026 07:50:12 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Fri, 5 Jun 2026 07:50:12 +0900    

Click here for diff

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   : c5194139cb4c9cf8284a6e433418c0323a7e7650    
  
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    

Click here for diff

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   : 0228d098ac48b6f82781c0382fe875d559f1042a    
  
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    

Click here for diff

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

pg_dump: scope indAttNames per index in getIndexes()

commit   : 94c02de89c2632eeb870899c89224ca1a23d2ae1    
  
author   : Alexander Korotkov <akorotkov@postgresql.org>    
date     : Wed, 3 Jun 2026 11:33:35 +0300    
  
committer: Alexander Korotkov <akorotkov@postgresql.org>    
date     : Wed, 3 Jun 2026 11:33:35 +0300    

Click here for diff

getIndexes() declared indAttNames and nindAttNames in the outer  
per-table loop, so the names collected for an index on expressions  
were carried over to the next plain index in the same table.  
  
This is an internal inconsistency rather than a user-facing bug.  
dumpRelationStats_dumper() only walks indexes that have pg_statistic  
rows, and ANALYZE only creates those for indexes with expressions,  
so the second index in the affected pair is not visited and the stale  
array is never consulted.  
  
Fix by moving the two variables into the inner per-index loop so each  
iteration starts with a clean slate.  
  
Author: Maksim Melnikov <m.melnikov@postgrespro.ru>  
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>  
Discussion: https://postgr.es/m/be5fc489-587e-421f-bbb8-adb43cfd50f4@postgrespro.ru  
Backpatch-through: 17  

M src/bin/pg_dump/pg_dump.c

Fix race in ReplicationSlotRelease() for ephemeral slots

commit   : f833c92077a1ba7fd8bb5d51dc466409e2fd33b0    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Wed, 3 Jun 2026 18:46:49 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Wed, 3 Jun 2026 18:46:49 +0900    

Click here for diff

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   : b3f13c0324d2e6540cc00076a1204719e5c91017    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 3 Jun 2026 12:47:26 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 3 Jun 2026 12:47:26 +0900    

Click here for diff

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   : cc0819e78ae321fd01bb40751be1f765b3932aaa    
  
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    

Click here for diff

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

psql: Fix issues with deferred errors in pipelines

commit   : 1e9bc4074beb7678bc2fed1a104929f8e9da1615    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 3 Jun 2026 08:58:29 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 3 Jun 2026 08:58:29 +0900    

Click here for diff

When an error is raised while processing a Sync message in a pipeline,  
like a deferred constraint violation, the error was not associated with  
the piped command and was not counted in available_results.  This caused  
assertion failures in discardAbortedPipelineResults(), keeping an  
incorrect state at pipeline exit, because the code assumed that the  
number of available and requested results would always be positive,  
expecting all the counters to be 0 at the end of a pipeline.  
  
This commit switches discardAbortedPipelineResults() and  
ExecQueryAndProcessResults() to take a softer approach when consuming  
and draining the results after an error.  If there are still piped syncs  
in the pipeline when it ends, we now attempt to consume them before  
leaving the pipeline mode.  
  
Alexander has been able to reach two assertion failures through his  
testing.  While investigating more this issue, I have bumped into two  
more.  Most of these cases are covered by the regression tests added in  
this commit, plus some cases with mixes of pipelines, deferred errors  
and results fetched.  Some of the tests discussed (like the backend  
termination one) could not be included in this commit but have been  
tested manually.  Another test scenario discussed involved the injection  
of an error state in the backend, that was able to trick libpq  
internally and put its queue out of sync.  This scenario is not going to  
happen in practice, but if we were to do something about it we would  
need to make libpq understand that it needs to fail in some cases but  
not block.  
  
Reported-by: Alexander Lakhin <exclusion@gmail.com>  
Author: Michael Paquier <michael@paquier.xyz>  
Discussion: https://postgr.es/m/19494-97a86d84fee71c47@postgresql.org  
Backpatch-through: 18  

M src/bin/psql/common.c
M src/test/regress/expected/psql_pipeline.out
M src/test/regress/sql/psql_pipeline.sql

doc: Correct the timeline for OAuth's shutdown_cb

commit   : 380a8b2ea024c33a35e7abc8628e7c4f52f9f9f9    
  
author   : Jacob Champion <jchampion@postgresql.org>    
date     : Fri, 29 May 2026 14:39:03 -0700    
  
committer: Jacob Champion <jchampion@postgresql.org>    
date     : Fri, 29 May 2026 14:39:03 -0700    

Click here for diff

During original feature development, the OAuth validator shutdown  
callback was invoked via before_shmem_exit(). That was changed to use a  
reset callback before commit, but I forgot to update the documentation  
for validator developers.  
  
Correct this and backport to 18, where OAuth was introduced. The  
callback is invoked whenever the server is "finished" with token  
validation. (We make no stronger guarantees here, in the hopes that this  
API might successfully navigate future multifactor authentication  
support and/or changes to the server threading model.)  
  
Reported-by: Zsolt Parragi <zsolt.parragi@percona.com>  
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>  
Reviewed-by: Chao Li <li.evan.chao@gmail.com>  
Discussion: https://postgr.es/m/CAN4CZFOuMb_gnLvCwRdMybg_k8WRNJTjcij%2BPoQkuQHDUzxGWg%40mail.gmail.com  
Backpatch-through: 18  

M doc/src/sgml/oauth-validators.sgml

Use term "referenced" rather than "dependent" in dependency locking

commit   : c8b4186d6eef1bb310708e02aa872947fba87e9f    
  
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    

Click here for diff

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   : c0bf1d89df29e81c6fdad64e0f7cde10f16322bd    
  
author   : Andres Freund <andres@anarazel.de>    
date     : Thu, 28 May 2026 11:34:11 -0400    
  
committer: Andres Freund <andres@anarazel.de>    
date     : Thu, 28 May 2026 11:34:11 -0400    

Click here for diff

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/utils/misc/stack_depth.c

commit   : e5d019fbdc12281f666a94d3d2cf8ad33ae2006a    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Thu, 28 May 2026 20:58:45 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Thu, 28 May 2026 20:58:45 +0900    

Click here for diff

The use_scram_passthrough option in postgres_fdw and dblink accepts  
only boolean values. However, unlike other boolean options such as  
keep_connections, its value was not previously validated.  
  
As a result, commands such as  
"CREATE SERVER ... OPTIONS (use_scram_passthrough 'invalid')"  
could succeed unexpectedly.  
  
This commit updates postgres_fdw and dblink to validate that  
use_scram_passthrough is assigned a valid boolean value, and throw an  
error for invalid input.  
  
Backpatch to v18, where use_scram_passthrough was introduced.  
  
Author: Fujii Masao <masao.fujii@gmail.com>  
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>  
Reviewed-by: Matheus Alcantara <matheusssilv97@gmail.com>  
Discussion: https://postgr.es/m/CAHGQGwF+-k-Ehsu5W94ZP7GxS3wiBd+mi0PfGTdJ_i2Yr0zR3g@mail.gmail.com  
Backpatch-through: 18  

M contrib/dblink/dblink.c
M contrib/postgres_fdw/option.c

Fix race between ProcSignalInit() and EmitProcSignalBarrier().

commit   : 1a9b1cc18e068e181f85ab8712ac4d2274d609ab    
  
author   : Masahiko Sawada <msawada@postgresql.org>    
date     : Wed, 27 May 2026 16:25:59 -0700    
  
committer: Masahiko Sawada <msawada@postgresql.org>    
date     : Wed, 27 May 2026 16:25:59 -0700    

Click here for diff

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   : c8cd3d6976f7af2eceff8421ec2fd0d2bdc8dc84    
  
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    

Click here for diff

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   : f9d5a52da4ca71d592e9cef55ed676136362b8b5    
  
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    

Click here for diff

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   : 12c9b8b422e27bc1fc1475379b29c177cc988589    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 27 May 2026 17:19:53 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 27 May 2026 17:19:53 +0900    

Click here for diff

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   : ae08eb1687e1def3521b3915dc31f83eb209377f    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 27 May 2026 14:48:59 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 27 May 2026 14:48:59 +0900    

Click here for diff

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   : 196b4b5ae612cc45a95fabf6248b3dfe389cf770    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Wed, 27 May 2026 10:35:18 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Wed, 27 May 2026 10:35:18 +0900    

Click here for diff

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   : 97b5c5aaad5dba2144215293d4b8438df693c13b    
  
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    

Click here for diff

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

Add stack depth check to QueueFKConstraintValidation().

commit   : 0480d84ee35f386d3d78b58488303f9f6ba1b4c2    
  
author   : Tom Lane <tgl@sss.pgh.pa.us>    
date     : Tue, 26 May 2026 11:58:25 -0400    
  
committer: Tom Lane <tgl@sss.pgh.pa.us>    
date     : Tue, 26 May 2026 11:58:25 -0400    

Click here for diff

QueueFKConstraintValidation() recurses through the partition hierarchy  
to queue child constraint validations and to mark child rows as  
validated.  With a sufficiently deep partition tree, this can result  
in a stack-overflow crash.  Defend against that as we do elsewhere.  
  
Bug: #19482  
Reported-by: Alexander Lakhin <exclusion@gmail.com>  
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>  
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>  
Discussion: https://postgr.es/m/19482-4cc37cbf52d55235@postgresql.org  
Backpatch-through: 18  

M src/backend/commands/tablecmds.c

Fix missed ReleaseVariableStats() in intarray's _int_matchsel().

commit   : e7544c518ab0943fc85e2a4b44df9f7561ad2d0c    
  
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    

Click here for diff

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

commit   : cd777e27e2038f2c39f0f2d5d68d45c67bdf89e8    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Tue, 26 May 2026 01:07:24 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Tue, 26 May 2026 01:07:24 +0900    

Click here for diff

Previously, dblink accepted the use_scram_passthrough option on  
foreign-data wrappers via ALTER FOREIGN DATA WRAPPER dblink_fdw  
OPTIONS, even though the setting had no effect there.  
  
use_scram_passthrough should be only meaningful for foreign servers  
and user mappings, so this commit updates dblink to accept the option  
only in those contexts.  
  
Backpatch to v18, where use_scram_passthrough was introduced.  
  
Author: Matheus Alcantara <matheusssilv97@gmail.com>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/CAHGQGwEJ8rZjmbOvCicyr4vbuLio082bNTde0WNoSWaWr9wVcg@mail.gmail.com  
Backpatch-through: 18  

M contrib/dblink/dblink.c
M contrib/dblink/expected/dblink.out
M contrib/dblink/sql/dblink.sql

commit   : 130396e6c034c26617c8a73be44f9640082fd490    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Tue, 26 May 2026 00:51:18 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Tue, 26 May 2026 00:51:18 +0900    

Click here for diff

Commit 97f6fc10fff changed postgres_fdw so that user-mapping settings  
override foreign server settings for use_scram_passthrough. This commit  
applies the same behavior to dblink.  
  
Backpatch to v18, where use_scram_passthrough was introduced.  
  
Author: Matheus Alcantara <matheusssilv97@gmail.com>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/CAHGQGwEJ8rZjmbOvCicyr4vbuLio082bNTde0WNoSWaWr9wVcg@mail.gmail.com  
Backpatch-through: 18  

M contrib/dblink/dblink.c
M contrib/dblink/t/001_auth_scram.pl
M doc/src/sgml/dblink.sgml

postgres_fdw: Give user mapping precedence for use_scram_passthrough

commit   : 88d7748d2ab7017c29c0f7bec04612b2680552d0    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Tue, 26 May 2026 00:46:31 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Tue, 26 May 2026 00:46:31 +0900    

Click here for diff

Previously, when use_scram_passthrough was specified on both a foreign server  
and a user mapping, the server-level setting took precedence over the  
user-mapping setting. This was inconsistent with the usual semantics of  
postgres_fdw options, where foreign server options provide shared defaults  
and user mapping options override them on a per-user basis.  
  
This commit updates postgres_fdw so that the user-mapping setting takes  
precedence when use_scram_passthrough is specified in both places. This  
matches the behavior of other connection options such as sslcert and sslkey.  
  
Backpatch to v18, where use_scram_passthrough was introduced. In v18,  
this only affects limited configurations that specify conflicting values  
at both the foreign server and user-mapping levels. In such cases, users  
would naturally expect the user-mapping setting to override the server-level  
setting, so changing the behavior should be minimally disruptive.  
Also keeping v18 as the only branch with different semantics for  
use_scram_passthrough would be unnecessarily confusing, so backpatch  
this fix to v18.  
  
Author: Matheus Alcantara <matheusssilv97@gmail.com>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/CAHGQGwEJ8rZjmbOvCicyr4vbuLio082bNTde0WNoSWaWr9wVcg@mail.gmail.com  
Backpatch-through: 18  

M contrib/postgres_fdw/connection.c
M contrib/postgres_fdw/t/001_auth_scram.pl
M doc/src/sgml/postgres-fdw.sgml

Fix size check in statext_dependencies_deserialize()

commit   : b5fd5723a6594f0d74cc05ce5971190b71efdd20    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 25 May 2026 14:38:59 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Mon, 25 May 2026 14:38:59 +0900    

Click here for diff

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   : b903d17927eecab8dd741eb71f04eee5a1182eff    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Sat, 23 May 2026 08:10:12 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Sat, 23 May 2026 08:10:12 +0900    

Click here for diff

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

Prevent setting NO INHERIT on partitioned NOT NULL constraints

commit   : 41247cdf695b99eb4b6359ef3d6bdcfbad321847    
  
author   : Fujii Masao <fujii@postgresql.org>    
date     : Fri, 22 May 2026 23:59:04 +0900    
  
committer: Fujii Masao <fujii@postgresql.org>    
date     : Fri, 22 May 2026 23:59:04 +0900    

Click here for diff

The documentation states that NOT NULL constraints on partitioned tables  
are always inherited by all partitions, and therefore cannot be declared  
NO INHERIT. While a check already existed to reject creating such  
constraints with NO INHERIT, previously the same check was missing for  
ALTER TABLE ... ALTER CONSTRAINT ... NO INHERIT.  
  
This commit adds the missing check so that attempting to set NO INHERIT  
on a partitioned NOT NULL constraint now fails.  
  
Backpatch to v18, where ALTER TABLE ... ALTER CONSTRAINT ... [NO] INHERIT  
was added.  
  
Author: Andreas Karlsson <andreas@proxel.se>  
Reviewed-by: Jim Jones <jim.jones@uni-muenster.de>  
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>  
Discussion: https://postgr.es/m/ecc985ad-6ec1-4094-a315-317943ca5f3f@proxel.se  
Backpatch-through: 18  

M src/backend/commands/tablecmds.c
M src/test/regress/expected/constraints.out
M src/test/regress/sql/constraints.sql

pg_recvlogical: Honor source cluster file permissions for output files

commit   : 89b4b3ae35d2f38aa0e12b147c92c99262c6d146    
  
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    

Click here for diff

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

psql: Make ParseVariableDouble reject values above max

commit   : e0c641ebbf0aab219bbe5fe0ed2be4d937f1fea1    
  
author   : Daniel Gustafsson <dgustafsson@postgresql.org>    
date     : Mon, 18 May 2026 08:33:36 -0700    
  
committer: Daniel Gustafsson <dgustafsson@postgresql.org>    
date     : Mon, 18 May 2026 08:33:36 -0700    

Click here for diff

ParseVariableDouble missed returning false after logging an error when  
the parsed value exceeded max, making the value assigned rather than  
rejected.  Backpatch down to v18 where this was introduced as part of  
the \WATCH_INTERVAL.  
  
Author: Sven Klemm <sven@tigerdata.com>  
Co-authored-by: Daniel Gustafsson <daniel@yesql.se>  
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>  
Discussion: https://postgr.es/m/CAMCrgp31p_5SDVi7dwnP39tTW5icQ0MWHA+N4kJdXgkL0PEy8w@mail.gmail.com  
Backpatch-through: 18  

M src/bin/psql/t/001_basic.pl
M src/bin/psql/variables.c

injection_points: Move some structs to new header injection_points.h

commit   : 20a4b06a1ea1396ab1ced0db96406b50fb3b603a    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Mon, 18 May 2026 11:11:44 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Mon, 18 May 2026 11:11:44 +0900    

Click here for diff

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   : dc3db3a8349bd164354ef5b6c94d1c0c2adc651c    
  
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    

Click here for diff

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   : d472bf14f2595926a96bf668936b2cc920b9a7d3    
  
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    

Click here for diff

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-18.sgml

Re-add regression tests for ltree and intarray

commit   : f45f418275b14fab6a074fee7081a89287b9149f    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Fri, 15 May 2026 18:02:47 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Fri, 15 May 2026 18:02:47 +0900    

Click here for diff

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   : ed0c4d5af2ef4b3d0880aba768fe7948f3e3e1e6    
  
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    

Click here for diff

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   : 1b0dd08157bf945909849c5e73d9e3f5b057c63b    
  
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    

Click here for diff

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   : 1cd37a7a8dc6bbd3127f4df6dddf1ae79b60f81e    
  
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    

Click here for diff

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   : 98dd6c2046965e51da015681e81c20109be46d71    
  
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    

Click here for diff

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   : 89192080f0a9599d121a8ba85a94b41b8c424cf5    
  
author   : Michael Paquier <michael@paquier.xyz>    
date     : Wed, 13 May 2026 14:43:46 +0900    
  
committer: Michael Paquier <michael@paquier.xyz>    
date     : Wed, 13 May 2026 14:43:46 +0900    

Click here for diff

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   : d9cd9b4d7e147fc4965195c765f191ac69593c43    
  
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    

Click here for diff

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