Restore vacuum_delay_point() in GIN posting-tree leaf vacuum
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
Dean Rasheed [Tue, 28 Jul 2026 08:44:23 +0000 (09:44 +0100)]
Avoid RETURNING side effects for FOR PORTION OF leftovers.
UPDATE/DELETE ... FOR PORTION OF inserts leftover rows for the
untouched parts of the original row. These hidden inserts should not
affect the command tag or ROW_COUNT, so they call ExecInsert() with
canSetTag set to false.
However, ExecInsert() still processed the RETURNING list whenever the
target ResultRelInfo had ri_projectReturning set. That caused
RETURNING expressions to be evaluated for leftover rows even though
their results were discarded. As a result, expressions with side
effects and information-leaking functions could be executed on the
leftover rows, in addition to the visibly updated or deleted row.
Fix by having ExecInsert() skip RETURNING processing when it is
handling an internal FOR PORTION OF leftover insert. Use both the
presence of a FOR PORTION OF clause and mtstate->operation ==
CMD_INSERT for this check, so that the auxiliary INSERT of a
cross-partition UPDATE with a FOR PORTION OF clause still processes
RETURNING normally.
Back-patch to v19, where support for FOR PORTION OF was added.
Author: Chao Li <lic@highgo.com> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com> Reviewed-by: Paul A Jungwirth <pj@illuminatedcomputing.com>
Discussion: https://postgr.es/m/07C125E5-F6ED-460C-A394-E6503DAE18FB@gmail.com
Backpatch-through: 19
Michael Paquier [Tue, 28 Jul 2026 01:49:26 +0000 (10:49 +0900)]
Fix portability issue in authentication test 003_peer
The mapped user name is built upon the OS user name of the environment
where the test is run. Depending on the characters used in the OS user
name, CREATE ROLE may not get parsed (the author has mentioned hyphens
as one case), causing a failure of the test.
Let's use double-quotes around the mapped user name, which should be a
solution good enough for the environments where this test tends to run.
The buildfarm issued no complaint over the years.
Oversight in 3c4e26a62c31, so backpatch down to v19. Perhaps 3c4e26a62c31 and this commit should be backpatched further down, but
let's leave that for another day, if it proves necessary.
Michael Paquier [Mon, 27 Jul 2026 23:33:23 +0000 (08:33 +0900)]
Fix propagation of indimmediate flag in index_create_copy()
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.
Tom Lane [Mon, 27 Jul 2026 20:19:24 +0000 (16:19 -0400)]
Further improve the names generated for indexes on expressions.
Commit 181b6185c failed to do anything useful with a whole-row Var,
deeming it "fishy". But it is legal to put such a Var into an
expression index column, so let's expand it as the name of the table.
Another problem reachable via that one is that we could generate an
empty index column name, which isn't really legal although by chance
nothing complained about it. It's not clear whether any other such
cases remain, but as cheap insurance let's use "expr" if the tree walk
fails to generate any text.
Reported-by: Chauhan Dhruv <chauhandhruv351@gmail.com>
Author: Chauhan Dhruv <chauhandhruv351@gmail.com> Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CANWwWcp_DCJjq8pomeqp6W=fbygvzXXQO028VDJ9_6sLPjQnVA@mail.gmail.com
Fix race condition when enabling logical decoding concurrently.
With wal_level = 'replica', logical decoding is enabled on demand
when the first logical replication slot is created:
When enabling logical decoding, EnableLogicalDecoding() flips the
shared logical_decoding_enabled flag and writes an
XLOG_LOGICAL_DECODING_STATUS_CHANGE record so that standbys follow the
status change. The initial "already enabled?" check and the WAL record
write happen under two separate acquisitions of
LogicalDecodingControlLock, since the lock must be released while
waiting for the ProcSignalBarrier: processes absorbing the barrier
acquire the same lock in shared mode.
Consequently, if two backends concurrently created the first logical
slots, both could pass the initial check and both write a
status-change record. The redundant record lands after the decoding
start point already reserved by the other backend's slot, so decoding
that slot processes the record and fails with "unexpected logical
decoding status change", as xlog_decode() assumes that no such record
can appear within the WAL range any slot decodes.
Fix by re-checking the status after re-acquiring the lock, so that
only the backend that actually performs the disabled->enabled
transition writes the WAL record.
Tom Lane [Mon, 27 Jul 2026 13:37:04 +0000 (09:37 -0400)]
Deparse FOR PORTION OF using the range column's current name.
Commit 8e72d914c recorded the range column's name in ForPortionOfExpr
and used that for deparsing FOR PORTION OF. This gives the wrong
answer if the ForPortionOfExpr is saved in a rule or SQL function and
then the column gets renamed. Drop the ForPortionOfExpr.range_name
field; instead fetch the current column name from the catalogs when
needed.
Also drop ForPortionOfState.fp_rangeName, which wasn't being used
anywhere.
Full disclosure: an earlier draft of this patch was made with
Claude Opus 4.8.
Reported-by: John Naylor <johncnaylorls@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Richard Guo <guofenglinux@gmail.com> Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CANWCAZYFEpJ5Oi45gi4q9Y6LYa4_oiAXxuNNWe-1ym-i0fF8Pw@mail.gmail.com
Backpatch-through: 19
pg_resetwal: do not allow zero next multixact offset
Offset 0 is the "invalid" marker in pg_multixact/offsets since offsets
went 64-bit and the allocator stopped skipping it. pg_resetwal could
still produce it via -O 0 or guessed control values, breaking the first
multixact created after the reset ("MultiXact n has invalid offset",
and vacuum of the affected table fails from then on). Reject -O 0 like
-m and -o already do, and guess 1 like initdb does.
Amit Kapila [Mon, 27 Jul 2026 03:36:05 +0000 (09:06 +0530)]
Fix issues in logical replication sequence synchronization.
1. Stop a running sequence synchronization worker when
ALTER SUBSCRIPTION ... DISABLE is executed. The worker did not reread its
subscription after starting a transaction, so it kept running with a stale
copy and missed the disable. It now calls maybe_reread_subscription()
after StartTransactionCommand(), matching the apply worker.
2. Restore the invariant that publisher-side synchronization slots are
dropped last during ALTER SUBSCRIPTION ... REFRESH PUBLICATION. The
slot-drop loop now runs after the sequence-removal loop, so the
non-transactional slot drops happen only after all catalog changes that
could still be rolled back on error.
3. Restore psql tab completion for
ALTER SUBSCRIPTION ... REFRESH PUBLICATION WITH (.
4. Make pg_stat_subscription report NULL for the fields that do not apply
to a sequence synchronization worker, which does not stream from a
walsender, and update the documentation accordingly.
5. Update the pg_subscription_rel.srsublsn catalog documentation to
describe its semantics for sequence rows.
Reported-by: Noah Misch <noah@leadboat.com>
Author: vignesh C <vignesh21@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 19, where it was introduced
Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com
Richard Guo [Mon, 27 Jul 2026 01:21:18 +0000 (10:21 +0900)]
Fix deparsing of JSON_ARRAY(subquery) with a FORMAT clause
Commit 8d829f5a0 introduced the JSCTOR_JSON_ARRAY_QUERY constructor
type so that ruleutils.c could deparse JSON_ARRAY(subquery) using its
original syntax, storing the transformed subquery in a new orig_query
field. However, the input FORMAT clause of JSON_ARRAY(subquery FORMAT
...) was not preserved for deparsing. The format was recorded only in
the executable expression kept in the func field, which ruleutils.c
does not inspect, so it is silently dropped.
This is more than cosmetic, because FORMAT JSON changes the result:
without it a text value is treated as a string to be quoted, while
with it the value is treated as already-formatted JSON.
To fix, record the input FORMAT in a new deparse-only field of
JsonConstructorExpr, alongside orig_query, and emit it in ruleutils.c.
Bump catalog version.
Author: Chao Li <li.evan.chao@gmail.com> Reviewed-by: Ewan Young <kdbase.hack@gmail.com> Reviewed-by: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/4C89B193-7D54-4705-9CF9-F0D484B9E099@gmail.com
Backpatch-through: 19
Michael Paquier [Mon, 27 Jul 2026 00:42:50 +0000 (09:42 +0900)]
Use direct hash lookup in logicalrep_partmap_invalidate_cb()
This replaces an O(N) hash_seq_search() loop by an O(1) lookup, removing
a TODO item, making the invalidation callback faster when dealing with
many relations. This can work because LogicalRepPartMap is keyed by a
partition OID, and a relmapentry's localreloid matches with it.
An assertion is added in logicalrep_partition_open() to enforce the fact
that localreloid matches with the hash key.
Author: DaeMyung Kang <charsyam@gmail.com>
Discussion: https://postgr.es/m/20260417174450.4158878-1-charsyam@gmail.com
Peter Geoghegan [Sun, 26 Jul 2026 16:49:56 +0000 (12:49 -0400)]
Add _bt_set_startikey row compare test coverage.
Add pg_regress tests that exercise the row compare logic that commit 7d9cd2df added to _bt_set_startikey. Also add tests that exercise the
_bt_set_startikey SAOP array path.
Author: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-Wz=KjQsD2W2a=b51uH905=0mF6Le4evhWkN2FL1+uRPhUg@mail.gmail.com
Backpatch-through: 19
Peter Geoghegan [Sat, 25 Jul 2026 21:13:00 +0000 (17:13 -0400)]
Add test coverage for nbtree backwards scans.
Backwards scans have unique concurrency rules: rather than unreservedly
trusting a saved left link, the scan optimistically rechecks its
pointed-to leaf page's right link (i.e. whether it still points back to
the page that _bt_readpage just read). Usually, the left sibling of the
just-read page won't have changed, in which case the scan can proceed
with reading the left sibling as planned. But it's possible that the
key space that the scan needs to read next is no longer covered by the
original left sibling page due to concurrent page splits and/or page
deletions. When that happens, the scan must recover by relocating the
new/current left sibling of the just-read page.
Test coverage for backwards scans was limited to the happy path. Add an
isolation test (and associated injection points) that test the recovery
path. This covers several distinct recovery scenarios (concurrent page
splits, concurrent page deletions, and minor variants thereof).
Author: Peter Geoghegan <pg@bowt.ie> Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-WzmD+jUBOpFS2jrnqqrdPSAjoxqyL9FPKaE1BtnY=8Nntg@mail.gmail.com
Peter Geoghegan [Sat, 25 Jul 2026 18:15:33 +0000 (14:15 -0400)]
Add tests for nbtree empty index predicate locking.
Add coverage for predicate locking of completely empty nbtree indexes,
where we must predicate lock the entire relation (instead of some
individual leaf page). Both paths that can find the index empty (and
must consider whether it's still empty after PredicateLockRelation
returns) are covered by a new isolation test that uses injection points.
Catalog relation scans skip the injection points. The waiting session
runs catalog queries of its own after arming the (session-local) points,
and could otherwise suspend itself with nothing lined up to wake it.
Follow-up to bugfix commits ce3f19e2 (the _bt_endpoint fix) and f9b7fc65
(the _bt_first/_bt_search fix).
Author: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-WzkNoTn3yXY0iGkSuavJ+sL8EROf+kitW+_2v2tJVWuKmA@mail.gmail.com
Peter Geoghegan [Sat, 25 Jul 2026 16:01:35 +0000 (12:01 -0400)]
Fix another empty nbtree index SSI race.
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
psql: Allow pg_read_all_stats to see database size in \l+
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.
Avoid reporting permission-denied publisher sequences as missing
Previously, if a sequence synchronization batch contained both a sequence
that had been dropped on the publisher and another for which the
replication role lacked SELECT privilege, the latter was reported
twice: once as a permission failure and again as missing on the
publisher.
This happened because the permission-denied sequence was not marked as
found on the publisher. As a result, when another sequence in the batch
was genuinely missing, the later missing-sequence check incorrectly
classified the permission-denied sequence as missing as well.
Fix this by marking the permission-denied sequence as found before
reporting the permission failure, so it is not later reported as
missing.
Document table_name, column_name, and schema_name in the CREATE
PUBLICATION and ALTER PUBLICATION reference pages. Also add anchors for
the ALTER PUBLICATION parameter list, matching the style already used by
CREATE PUBLICATION.
Author: Peter Smith <smithpb2250@gmail.com> Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAHut+Ptekz+TO4ui8-fiBm4Y+O2v=HQnkK_cW4G=w9ep8654EA@mail.gmail.com
Commit fd366065e06 added tests intended to verify that rows inserted
on the publisher are replicated to the subscriber when using multiple
publications, with one excluding the target table via EXCEPT and
another including it.
However, the tests queried the publisher instead of the subscriber.
Since the rows were inserted directly into the publisher, the checks
would always succeed, providing no coverage of replication.
Fix this by querying the subscriber so the tests verify the replicated
state.
For subscriptions using SERVER, changing the owner can change the
effective connection string. However, ALTER SUBSCRIPTION ... OWNER TO
did not validate the generated conninfo for the new owner.
As a result, ownership could be transferred to a non-superuser whose
generated connection string did not satisfy password_required=true.
The ownership change succeeded, but the subscription would fail later
when the worker or another command tried to connect.
Fix this by making ALTER SUBSCRIPTION ... OWNER TO validate the new
owner's generated conninfo with walrcv_check_conninfo().
Backpatch to v19, where SERVER subscriptions were introduced.
Improve the documentation for pg_stat_recovery in several ways:
- Mention the view in high-availability.sgml as a way to monitor
recovery state and replay progress, alongside the existing recovery
information functions.
- Clarify that the view returns at most one row, not exactly one row,
and no rows to users who lack the pg_read_all_stats privilege.
- Correct the description of last_replayed_end_lsn to clarify that it
is the end LSN of the last replayed record plus one.
- Document that replay_end_tli equals last_replayed_tli when no WAL
record is currently being replayed.
- Clarify that current_chunk_start_time is NULL until streaming WAL
has been received.
Backpatch to v19, where pg_stat_recovery was introduced.
Michael Paquier [Thu, 23 Jul 2026 07:48:40 +0000 (16:48 +0900)]
Fix socket_putmessage_noblock() to call socket_putmessage()
socket_putmessage_noblock() used pq_putmessage(), which redirects to
PqCommMethods->putmessage. In the common cases, this points to
socket_putmessage(), but it would become incorrect if PqCommMethods
points to a different implementation.
This change may look like a bug, but as far as I can see this is mostly
cosmetic. The code is able to work currently, as the repalloc() done in
the noblock() call ensures that the blocking path of internal_putbytes()
is never reached. The issue has gone unnoticed since 2bd9e412f92b.
Michael Paquier [Thu, 23 Jul 2026 07:09:13 +0000 (16:09 +0900)]
doc: Improve description of pg_stat_activity.backend_type
The documentation of pg_stat_activity used an incomplete list of values
for backend_type. While on it, it is improved to use an itemized list,
now ordered alphabetically, with a short description about each item.
Michael Paquier [Thu, 23 Jul 2026 05:37:39 +0000 (14:37 +0900)]
injection_points: Clear waiter slot on error and exit
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.
Amit Kapila [Thu, 23 Jul 2026 05:16:42 +0000 (10:46 +0530)]
Reject sequence synchronization against pre-PostgreSQL 19 publishers.
Sequence synchronization requires the page_lsn field returned by
pg_get_sequence_data(), which was added in PostgreSQL 19. Previously,
requesting sequence synchronization against an older publisher (via
ALTER SUBSCRIPTION ... REFRESH SEQUENCES or by running
ALTER SUBSCRIPTION ... CONNECTION on a disabled subscription with
sequences in the INIT state and subsequently enabling the subscription)
would cause the sequence synchronization worker to repeatedly fail with a
confusing "invalid query response" error.
Check the publisher's server version up front in both
AlterSubscription_refresh_seq() and copy_sequences(), and error out
immediately when it predates PostgreSQL 19.
Also document the PostgreSQL 19 publisher requirement for sequence
replication in the logical replication documentation and in
ALTER SUBSCRIPTION ... REFRESH SEQUENCES.
Reported-by: Noah Misch <noah@leadboat.com>
Author: vignesh C <vignesh21@gmail.com> Reviewed-by: Shveta Malik <shveta.malik@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com
Robert Haas [Wed, 22 Jul 2026 12:47:44 +0000 (08:47 -0400)]
walsummarizer: Guard against WAL files whose tail ends are not valid.
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.
Michael Paquier [Wed, 22 Jul 2026 00:52:04 +0000 (09:52 +0900)]
Improve lookup_type_cache() handling on out-of-memory errors
If an error happens during the initialization of the TYPEOID catcache,
as part of lookup_type_cache(), the error handling of that lookup would
cause an assertion failure via finalize_in_progress_typentries(), called
during error recovery, the presence of an in-progress type OID causing
a catcache initialization outside of a transaction context.
The in-progress list is now delayed to happen after the initial entry
lookup. Alexander Lakhin has found a fancy way to reproduce the
problem, with the injection of probabilistic memory allocation failures.
This problem is unlikely going to show up in practice. Like the other
changes of this kind, no backpatch is done.
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
Discussion: https://postgr.es/m/95c64dc2-3abe-4f4e-b285-4c681f565d9f@gmail.com
Michael Paquier [Tue, 21 Jul 2026 23:15:00 +0000 (08:15 +0900)]
Add new pgstats routine to split pending data setup
This commit adds pgstat_prep_pending_from_entry_ref(), a new pgstats
routine that is able to prepare an existing PgStat_EntryRef to receive
pending stats. This split gives a way for callers to obtain first a
reference via pgstat_get_entry_ref(), then set up pending data as two
separate, distinctive, steps.
Previously, the only way to get an entry reference with pending data
ready was pgstat_prep_pending_entry(), which bundles lookup, creation,
and pending setup in a single call. Callers that need finer control
over the entry creation had no way to attach pending data to an
already-obtained entry reference. One case where this has shown to
matter for a stats kind is where one wants to check some capacity (for
example where a GUC bounds the maximum numer of entries allowed) before
deciding if a new entry should be created. So this split can help in
reducing calls to pgstat_get_entry_ref(), meaning less shmem hash table
lookups.
The only logical ordering change is that pgStatPendingContext is
initialized after calling pgstat_get_entry_ref() in
pgstat_prep_pending_entry(). This does not matter in practice.
pgstat_prep_pending_entry() is refactored to use the new function
internally. All the existing callers are unchanged. Existing
out-of-core custom stats kinds should see no impact.
Author: Sami Imseih <samimseih@gmail.com> Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com> Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAA5RZ0sV+TsLejUMhAM=PJoOm8u-t8ru7B67KvyLCy=19sM87g@mail.gmail.com
Peter Eisentraut [Tue, 21 Jul 2026 13:27:02 +0000 (15:27 +0200)]
Message style fixes
Change DETAIL messages to conform to the style guide by capitalizing
the first word of sentences and ending sentences with a period.
Author: Peter Smith <peter.b.smith@fujitsu.com> Reviewed-by: Chao Li <li.evan.chao@gmail.com> Reviewed-by: vignesh C <vignesh21.gmail.com> Reviewed-by: Xiaopeng Wang <wxp_728.163.com> Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://www.postgresql.org/message-id/flat/CAHut%2BPszSntkUgN%2BQa9matGY6MLEoFGSuVbuKDgnnTdZ7YPRwg%40mail.gmail.com
Michael Paquier [Tue, 21 Jul 2026 07:50:18 +0000 (16:50 +0900)]
Improve generate_partition_qual()'s cache handling on out-of-memory errors
An in-flight failure when trying to set rd_partcheckcxt or
rd_partcheck, while for example doing an allocation in copyObject(),
would leave a backend cache in a corrupted state. The operations are
now ordered so as we avoid a leak in the cache memory context and a
semi-filled cache state when an allocation failure happens.
This is unlikely going to be hit in practice. Like the other
improvements of this kind, no backpatch is done.
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
Discussion: https://postgr.es/m/95c64dc2-3abe-4f4e-b285-4c681f565d9f@gmail.com
Peter Eisentraut [Tue, 21 Jul 2026 06:33:25 +0000 (08:33 +0200)]
Test what BEFORE UPDATE triggers do to FOR PORTION OF
If a BEFORE trigger changes NEW.valid_at, what is the interaction with
FOR PORTION OF? This commit gives a test to capture our current
behavior: The trigger's change replaces the value we computed
automatically, but it does not change the bounds of the temporal
leftovers.
This matches the behavior of MariaDB. On the other hand, DB2 rejects
changing the start/end columns of a PERIOD. Since we don't have
PERIODs, we can't reject the change at trigger definition time as DB2
does, but we could reject it at run time by comparing the values
before and after running triggers.
Author: Paul A. Jungwirth <pj@illuminatedcomputing.com>
Discussion: https://www.postgresql.org/message-id/CA%2BrenyV3Cr9BvWsPeb1t8b%3DPk24apuzyGbubAEs_YsgLUTfXpg%40mail.gmail.com
Amit Kapila [Tue, 21 Jul 2026 03:53:11 +0000 (09:23 +0530)]
Allow logical replication workers to ignore default_transaction_read_only.
Sequence synchronization updates sequence state via setval(), which
explicitly calls PreventCommandIfReadOnly(). If
default_transaction_read_only is enabled on the subscriber, this causes
sequencesync workers to fail with "cannot execute setval() in a read-only
transaction". Apply and tablesync workers are not affected, since they
write via direct heap access rather than through these read-only-checked
functions.
Rather than special-casing sequencesync, override
default_transaction_read_only to "off" for all logical replication workers
in InitializeLogRepWorker(), the same way session_replication_role and
search_path are already forced there. This keeps the initialization
uniform.
For PG-19, we kept the fix narrow by overriding
default_transaction_read_only to "off" only for sequencesync workers.
Reported-by: Noah Misch <noah@leadboat.com>
Author: vignesh C <vignesh21@gmail.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com
Add logical decoding status to pg_control_checkpoint().
Commit 8108765f04b added the logical decoding status to the
pg_controldata output, but overlooked the pg_control_checkpoint() SQL
function, which reports the same checkpoint information. This commit
adds a logical_decoding column to pg_control_checkpoint(), placed
after full_page_writes to match the pg_controldata output order.
Fix recovery target test waiting on unavailable WAL
Buildfarm member skink reported a failure in
recovery/003_recovery_targets after commit d5751c33cc3. The newly
added recovery_target_xid set-then-cleared test could time out while
waiting for pg_last_wal_replay_lsn() to reach the expected LSN.
The test recorded lsn6 after calling pg_switch_wal(). As a result,
lsn6 pointed into the next WAL segment, but pg_switch_wal() only
archived the previous one. Since the standby in this test restores WAL
from the archive only, it could not obtain the segment containing
lsn6 and waited indefinitely.
Fix this by recording lsn6 before calling pg_switch_wal(), so the
archived WAL contains the LSN that the standby is waiting for.
Robert Haas [Mon, 20 Jul 2026 17:36:39 +0000 (13:36 -0400)]
doc: Granting TRIGGER or REFERENCES on table is dangerous.
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.
Fix restore of partitions with exclusion constraints
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
Recovery target parameters are postmaster-startup GUCs, but their
assign hooks previously did more than assign individual parameter
values. They also updated the global recoveryTarget state and raised
ERROR if more than one recovery target appeared to be set.
This was not a good fit for GUC assign hooks. Assign hooks should not
throw ERROR, and deriving cross-parameter state while individual GUCs
are still being assigned makes the result depend on assignment order
rather than the final configuration.
For example, setting one recovery target and then setting another
recovery_target_* parameter to an empty string could clear
recoveryTarget, causing recovery to proceed with no target even
though a valid target remained configured.
Fix this by having the assign hooks only store their own parameter
values. The effective recoveryTarget is now derived once from the
final recovery_target* settings in
validateRecoveryParameters(), which also rejects configurations that
specify more than one recovery target with FATAL. This preserves the
expected behavior for repeated assignments of the same GUC, treats empty
values as "not set", and removes cross-GUC validation from the assign
hooks.
Allow PostgreSQL::Test::Cluster::start() to pass postmaster options
Previously, tests that needed extra postmaster command-line options had
to invoke pg_ctl start directly, because
PostgreSQL::Test::Cluster::start() provided no way to pass them. That
bypassed the test framework's postmaster PID tracking, so a postmaster
could be left running if the test failed after startup.
Add an options parameter to
PostgreSQL::Test::Cluster::start(), which is passed to pg_ctl's
--options argument. This allows tests to use start() while
preserving the framework's normal cleanup behavior.
Commit 6f6f284c7ee4 introduced use of LSN_FORMAT_ARGS across the whole
tree to remove use of manual bit-shifting, and commit 2633dae2e487
changed the printf format to be %X/%08X; however commit 28d534e2ae0a
violated both conventions by reintroducing the old manual-shift style
with the deprecated %X/%X format in one debug message. Make that new
message conform to our style.
Michael Paquier [Mon, 20 Jul 2026 06:52:18 +0000 (15:52 +0900)]
Improve pgstat_get_entry_ref_cached() behavior on out-of-memory errors
A failure in allocating a new cache entry in the backend-level hash
table holding references to shared stats entries would leave the table
in an inconsistent state, crash or FATAL at session exit, depending on
if there are pending stats.
Rather than leaving things in an inconsistent state on OOM, the code is
switched to use MemoryContextAllocExtended(MCXT_ALLOC_NO_OOM), so as an
allocation failure leads to a cleanup of the hash table before issuing
the allocation error.
The problem is unlikely going to show up in practice, so no backpatch is
done. Note that shared memory is not impacted, only a backend-level
hash table.
Reported-by: Alex Masterov <amasterov@gmail.com>
Discussion: https://postgr.es/m/CA+8z=zumV9sscgK=j1Es+-564maVoO9CMDdB9CsW9=FCziCj3w@mail.gmail.com
Peter Eisentraut [Mon, 20 Jul 2026 06:38:08 +0000 (08:38 +0200)]
Fix RLS checks for FOR PORTION OF leftover rows
UPDATE/DELETE FOR PORTION OF may insert leftover rows to preserve the
parts of the old row that are outside the target range. Those inserts
go through ExecInsert(), which checks RLS policies using
WCO_RLS_INSERT_CHECK.
However, the rewriter only added RLS WITH CHECK options for the
original statement command. For UPDATE, that meant only
WCO_RLS_UPDATE_CHECK options were available, so ExecInsert() skipped
them. For DELETE, no RLS WITH CHECK options were added at all. As a
result, leftover rows could be inserted even when they violated INSERT
RLS policies.
Fix this by adding INSERT RLS WITH CHECK options for UPDATE/DELETE FOR
PORTION OF target relations. Also add regression coverage for both
UPDATE and DELETE, including cases where allowed leftovers still
succeed and disallowed leftovers are rejected.
Author: Chao Li <lic@highgo.com> Co-authored-by: Paul A Jungwirth <pj@illuminatedcomputing.com> Reviewed-by: Paul A Jungwirth <pj@illuminatedcomputing.com> Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/6C34A987-AC50-4477-BD71-2D4AFEE1A589%40gmail.com
Discussion: https://www.postgresql.org/message-id/flat/CAJTYsWWdeBkoH5g8D-k9LDw9ciqsMxb21EJSiFXAzP4J%3DXyxOQ%40mail.gmail.com
Amit Kapila [Mon, 20 Jul 2026 05:41:45 +0000 (11:11 +0530)]
Handle concurrent sequence refreshes.
'ALTER SUBSCRIPTION ... REFRESH SEQUENCES' can race with a running
sequence synchronization worker. If the worker has fetched a sequence's
value from the publisher but not yet marked it READY, a concurrent refresh
that resets the sequence to INIT can be overwritten by the worker's stale
value, silently losing the refresh request.
Handle this by stopping any running sequence sync worker before resetting
the sequences to INIT. This is race-free because AlterSubscription()
already holds AccessExclusiveLock on the subscription object. That lock
blocks a running worker's UpdateSubscriptionRelState(), which takes
AccessShareLock on the object, and also any worker the apply worker
re-launches, because a new worker takes AccessShareLock on the object in
InitializeLogRepWorker() before it reads pg_subscription_rel. Such a
worker cannot act on the sequence states until the refresh commits, by
which time they are reset to INIT and it will synchronize the latest
publisher values.
Reported-by: Noah Misch <noah@leadboat.com>
Author: Amit Kapila <amit.kapila16@gmail.com> Reviewed-by: vignesh C <vignesh21@gmail.com> Reviewed-by: Shveta Malik <shveta.malik@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com
Richard Guo [Mon, 20 Jul 2026 03:13:11 +0000 (12:13 +0900)]
Skip unnecessary get_relids_in_jointree() when there are no PHVs
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
Peter Geoghegan [Mon, 20 Jul 2026 02:15:37 +0000 (22:15 -0400)]
Run nbtree test module tests under autoconf builds
Commit 1e4e5783e added the src/test/modules/nbtree test module, but only
registered it in the meson build, not in the module list in
src/test/modules/Makefile. As a result, autoconf builds never ran the
module's tests.
To fix, add the module to the Makefile's lists of
injection-point-dependent modules.
Fix parsing of underscores in pg_plan_advice occurrence numbers
The pg_plan_advice scanner recognizes underscores as digit separators
just like the core parser, but used strtoint() to convert occurrence
numbers which does not support underscores. Consequently, advice such
as SEQ_SCAN(x#1_0) failed to parse. Fix by using pg_strtoint32_safe()
like the core scanner, and also add regression test coverage.
This bug was independently found and reported by Lukas Fittl and Chao
Li. Backpatch down to v19 where pg_plan_advice was introduced.
Author: Chao Li <lic@highgo.com> Co-authored-by: Daniel Gustafsson <daniel@yesql.se> Reported-by: Lukas Fittl <lukas@fittl.com> Reported-by: Chao Li <li.evan.chao@gmail.com> Reviewed-by: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Lukas Fittl <lukas@fittl.com>
Discussion: https://postgr.es/m/22E2ECE0-B768-43D5-8575-61C3EBC2E4E8@gmail.com
Discussion: https://postgr.es/m/CAP53PkzKeD=t90OfeMsniYrcRe2THQbUx3g6wV17Y=ZtiwmWTQ@mail.gmail.com
Backpatch-through: 19
Remove redundant null-treatment check in window function dedup.
Commit 25a30bbd423 (IGNORE NULLS / RESPECT NULLS for window functions)
made ExecInitWindowAgg() treat two otherwise-equal window functions as
duplicates only when their ignore_nulls settings also matched:
if (i <= wfuncno && wfunc->ignore_nulls == perfunc[i].ignore_nulls)
That extra term reads WindowStatePerFuncData.ignore_nulls, but the field
was never populated when a per-function entry was filled in, so it stayed
zero from palloc0_array(). Consequently a duplicate call carrying
IGNORE NULLS or an explicit RESPECT NULLS never matched an identical
earlier entry and was needlessly given its own per-function slot and
evaluated twice. (Results stayed correct; this was a missed sharing, not
a wrong answer.)
The extra term is in fact redundant. WindowFunc.ignore_nulls is a plain
scalar field with no pg_node_attr, so _equalWindowFunc() already compares
it; the preceding equal() call therefore never matches two WindowFuncs
that differ only in null treatment. If equal() matches, ignore_nulls
necessarily matched too, so the term can never change the outcome, and
WindowStatePerFuncData.ignore_nulls existed only to feed it.
Rather than populate the shadow field, drop the redundant term and the
field (and adjust the now-stale comment) and let equal() do the work.
That fixes the same bug while removing the hand-maintained duplicate
state that caused it, so it cannot silently drift again.
Author: Chao Li <li.evan.chao@gmail.com> Co-authored-by: Ewan Young <kdbase.hack@gmail.com> Reviewed-by: Tatsuo Ishii <ishii@postgresql.org>
Discussion: https://postgr.es/m/5D2C9081-5DFE-4E27-AB14-7358238EA1BC%40gmail.com
Backpatch-through: 19
Commit 54cd6fc83 set the version argument for the stats-import functions
introduced by that commit, which is of type int, using UInt32GetDatum,
not Int32GetDatum. This would be completely harmless as it's positive
and currently ignored in the functions, but let's fix that code to use
Int32GetDatum for consistency.
Tom Lane [Sat, 18 Jul 2026 18:09:10 +0000 (14:09 -0400)]
Fix edge case in remove_useless_result_rtes() with outer joins.
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
Tom Lane [Sat, 18 Jul 2026 16:57:42 +0000 (12:57 -0400)]
Restore the ability to use | and -> as prefix operators.
Commit 2f094e7ac changed the parser to treat these as built-in
operator names, where before they were just generic Op. While
it correctly gave them the same precedence as Op and added new
productions to allow them to still be used as infix operators,
it missed allowing them to still be used as prefix operators.
At least one extension expects to be able to do that, so add
the necessary productions.
Bug: #19558 Reported-by: Pierre Senellart <pierre@senellart.com>
Author: Pierre Forstmann <pierre.forstmann@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19558-ad1fca59a3a471a0@postgresql.org
Backpatch-through: 19
Jeff Davis [Sat, 18 Jul 2026 16:22:40 +0000 (09:22 -0700)]
Fix REASSIGN OWNED for subscriptions in other databases.
Subscription objects are conceptually database-local objects, but
pg_subscription is a shared catalog so that the launcher process can
scan it.
Check readers of pg_subscription to ensure that, unless it's the
launcher process, it filters by MyDatabaseId. Most readers were
already doing so, but this commit fixes REASSIGN OWNED and adds guards
to catch other problems in the future. Also, clarify documentation.
That commit fixed a race that could leave stale sequence values on the
subscriber after 'ALTER SUBSCRIPTION ... REFRESH SEQUENCES'. It did so by
raising an ERROR during 'ALTER SUBSCRIPTION ... REFRESH SEQUENCES'
whenever a sequence synchronization worker was already running for the
subscription.
That approach caused intermittent buildfarm failures, because the existing
tests did not ensure the sequencesync worker had stopped before executing
'ALTER SUBSCRIPTION ... REFRESH SEQUENCES'. While discussing how to fix
the tests, we concluded that blocking the command while a sequencesync
worker is running is inconvenient for users. So we will fix the original
race differently in a follow-up commit.
Reported-by: Tom Lane <tgl@sss.pgh.pa.us>
Author: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/3614163.1784163070@sss.pgh.pa.us
Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com
Jeff Davis [Fri, 17 Jul 2026 23:41:14 +0000 (16:41 -0700)]
Generate unicode_limits.h.
To ensure we do not overflow a size_t while case mapping on a 32-bit
platform, we need to know the maximum amount a UTF8 string can expand.
Calculate that maximum while generating unicode tables as a part of
the update-unicode target, and output into a new header
unicode_limits.h. Minor refactoring along the way.
Add a StaticAssertDecl to check that a MaxAllocSize text value
expanded by that amount would still have a length that fits in
size_t. (We couldn't actually create a new text value out of that, but
we still need to avoid overflow.)
Reported-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/3213927.1783950167@sss.pgh.pa.us
Tom Lane [Fri, 17 Jul 2026 22:08:23 +0000 (18:08 -0400)]
Fix yet another portability problem in new NLS test.
Álvaro reported offlist that his machine was passing the new-in-v19
nls.sql test in "make check" but not in "make installcheck". On
investigation, the cause turned out to be that he has LANGUAGE set in
his environment, and with (at least recent versions of) glibc that
overrides LC_MESSAGES and friends, as per previous research by Bryan
Green. "make check" works because pg_regress unsets LANGUAGE before
starting the postmaster, but in installcheck mode we're exposed to
the prevailing value and we lose.
We're already hacking the value of LANGUAGE in this test for Solaris,
so let's just extend that to unsetting LANGUAGE on every other platform.
Reported-by: Álvaro Herrera <alvherre@kurilemu.de> Diagnosed-by: Andrew Dunstan <andrew@dunslane.net>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/a337896e-5bff-490b-afc9-c545f06c014c@gmail.com
Backpatch-through: 19
Turn visibilitymap_clear() Assert back into an error
Commit ed62d26caca fixed a bug in clearing the visibility map and, while
doing so, made some incidental changes to visibilitymap_clear(). One of
them replaced the error thrown when the wrong buffer is passed to
visibilitymap_clear() with an Assert().
While anyone adding a new visibilitymap_clear() caller should be running
assert-enabled builds, visibilitymap_set() still reports the same
wrong-buffer condition with an elog(ERROR), so visibilitymap_clear()
should also do so for consistency. This change was also unrelated to
the bug fix and is better made as a separate commit. Restore the error.
A postcommit review discovered that GROUP BY ALL missed our special
handling of entries that also appear in an ORDER BY in the query.
This caused the query to return wrong results when ORDER BY
specifies non-default equality semantics. While this should be
fixable with some refactoring, doing it cleanly seems like too
much code churn for late beta. We'll revert and try again in v20.
The reverted commit also included some additional comment wordsmithing
and docs cleanup, which are retained as they weren't connected to the
reverted feature.
catversion bump needed due to change in struct Query.
Reported-by: Chao Li <li.evan.chao@gmail.com>
Author: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/5243308F-8E5C-45AA-828C-FAD96C4F34DA@gmail.com
Backpatch-through: 19
Peter Geoghegan [Fri, 17 Jul 2026 19:53:10 +0000 (15:53 -0400)]
Fix GiST index-only scan column alignment issue.
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
Andres Freund [Fri, 17 Jul 2026 15:43:52 +0000 (11:43 -0400)]
ci: Generate crashlogs on Windows
This configures cdb.exe to log all crashes to
"<workspace>\crashlogs\crashlog-<pid-in-hex>.txt" (as it was previously set up
for cirrus-ci based CI). The upload logs step already collects these logs.
The logic is copied from the generation of Postgres CI Windows images for
cirrus-ci [1]. Since this would be too long to include inline in pg-ci.yml,
it is implemented as 'src/tools/ci/gha_setup_windows_debugger.ps1' script.
Author: Nazir Bilal Yavuz <byavuz81@gmail.com> Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CAN55FZ1BgsXSTzOpehnMa4NzWL8Aivsxx-di7-VT6bZ3j2Omow%40mail.gmail.com
Discussion: https://postgr.es/m/iggjozfshwbqpv33x5jqwtju5k5zrkyu3257dlifxkhtpg7eoq@k2ccyrdi5dtu
Backpatch-through: 19, where GHA CI was added
Andres Freund [Fri, 17 Jul 2026 15:43:52 +0000 (11:43 -0400)]
ci: Use optimized build for mingw
The test runtime dominates over the compile time on GHA. Note that we just
need to remove options, as postgres's default is debugoptimized.
Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Discussion: https://postgr.es/m/a2ejn7lfqolutzz7kozalbhy3bixdrujb4buc3pgbtlk4am2ba@wbv6v7riia33
Backpatch-through: 19, where GHA CI was added
Andres Freund [Fri, 17 Jul 2026 15:23:18 +0000 (11:23 -0400)]
meson: Fix ccache issues when using precompiled headers with gcc
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
Commit e1d917182 added support for base64url encoding, a base64 variant
intended to be safe for usage in URLs and filenames. The padding rules
for base64url and base64 differ in that base64url require no extra '='
padding, but the commit unintentionally relaxed this requirement for
base64 as well. Fix by making sure that the truncation logic check
for the encoding and add a test to make sure.
Backpatch down to v19 where support for base64url was introduced.
Author: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: David E. Wheeler <david@justatheory.com>
Discussion: https://postgr.es/m/3258FC72-F5E1-40B9-B5D7-64478CAF7728@yesql.se
Backpatch-through: 19
Restrict pg_stat_io entries for data checksum processes
The data checksums launcher and workers were exposed in pg_stat_io
with the same broad set of object/context combinations as general
background workers. However, several of those entries can never
accumulate I/O statistics for these processes, such as bulkwrite,
relation init, temporary relation, and launcher vacuum entries.
Teach pgstat_tracks_io_object() and pgstat_tracks_io_op() about the
actual I/O performed by the data checksum processes. Keep the entries
needed for catalog scans, including bulkread catalog scans, worker
relation processing with a vacuum access strategy, and WAL writes and
initialization, while excluding WAL reads and other object/context
combinations that can never be used.
Amit Kapila [Fri, 17 Jul 2026 04:17:33 +0000 (09:47 +0530)]
Doc: Clarify DROP SUBSCRIPTION behavior after SET (slot_name = NONE).
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
Peter Geoghegan [Thu, 16 Jul 2026 22:55:36 +0000 (18:55 -0400)]
Fix wrong variable offset sanity check.
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
Michael Paquier [Thu, 16 Jul 2026 22:40:10 +0000 (07:40 +0900)]
Remove SQL function getpgusername()
Since 457ac0331cd3, current_user() is the recommended way to get access
to this information, and getpgusername() was marked as deprecated since,
without being documented.
Bump catalog version.
Reported-by: Thom Brown <thom@linux.com>
Discussion: https://postgr.es/m/CAA-aLv44sPoKhHZqBvhqRdrFUEKwatGEmXBtqC360UuD5Lt7Nw@mail.gmail.com
The logical decoding status is stored in checkpoint records and used
to restore the status at server startup, but pg_controldata did not
show it. This information is useful for diagnosing issues around the
dynamic activation and deactivation of logical decoding.
Correct logical decoding status at end of recovery with minimal WAL level.
Crash recovery running with wal_level='minimal' can replay an
XLOG_LOGICAL_DECODING_STATUS_CHANGE record that activates logical
decoding, if the server previously ran with a higher wal_level and
crashed after the last logical slot was dropped but before the
checkpointer deactivated logical decoding. Replaying such a record is
correct since it reflects the status at the time it was
written. However, UpdateLogicalDecodingStatusEndOfRecovery() asserted
that logical decoding is never active with wal_level='minimal',
causing an assertion failure at the end of recovery. In production
builds, logical decoding would remain active while running with
wal_level='minimal'.
Instead of special-casing wal_level='minimal', recompute the status at
the end of recovery as usual: no logical slot can exist with
wal_level='minimal' as RestoreSlotFromDisk() would have rejected it,
so the recomputation always deactivates logical decoding in this case,
also writing the corresponding status change record.
Reject infinite and out-of-range interval shifts in uuidv7().
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.
Tom Lane [Thu, 16 Jul 2026 15:56:01 +0000 (11:56 -0400)]
In transformIndexStmt, transform index expressions in INCLUDING.
Process these just like the adjacent loop for expressions in regular
index columns. This logic was originally omitted because there was
no intention of supporting index expressions in INCLUDING.
There's still no near-term intention of that, but without this change
the ChooseIndexExpressionName code added by 181b6185c spits up on
expressions in INCLUDING: that expects to handle parse-transformed
expressions, and it runs before we reach the place that is currently
supposed to throw the "not supported" error. We could fix this
problem in other ways, but this way avoids contorting the logic,
and it results in less code to be revised not more if we ever get
around to supporting INCLUDING expressions.
Reported-by: Maaz Syed Adeeb <maaz.adeeb@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us> Test-authored-by: Maaz Syed Adeeb <maaz.adeeb@gmail.com>
Discussion: https://postgr.es/m/CAG+FJqOxYj=sVyHcys64h9DbvzP6EUPGHJ7oKj-PW=Qp5Ebk_g@mail.gmail.com
Handle concurrent sequence drops during synchronization
Commit d4a657b0a4d added a call to has_sequence_privilege() while
fetching sequence information from the publisher, so that
publisher-side permission failures could be distinguished from missing
sequences. It also assumed that has_sequence_privilege() could never
return NULL, and asserted accordingly.
However, that assumption was incorrect. If a sequence is dropped after
the synchronization worker collects its metadata but while fetching the
sequence information, has_sequence_privilege() can return NULL.
This can trigger the assertion failure. This was also reported in
a buildfarm failure on member culicidae.
Fix this by treating a NULL result from has_sequence_privilege() as
indicating that the sequence was dropped concurrently, and report it as
a missing sequence instead of asserting that the result is never NULL.
postgres_fdw: stabilize terminated-connection regression tests
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
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.
Peter Eisentraut [Thu, 16 Jul 2026 09:47:41 +0000 (11:47 +0200)]
Require ICU 55 or later
Support for older versions is removed. Since we no longer support
RHEL 7, we don't need to support these old versions anymore. This
allows a fair amount of code cleanup, including some code blocks that
specifically catered to old versions that probably received very
little actual testing and use.
Peter Eisentraut [Thu, 16 Jul 2026 09:47:41 +0000 (11:47 +0200)]
Make PL/Tcl require Tcl 8.6 or later
Support for Tcl 8.5 and 8.4 is removed. Since we no longer support
RHEL 7, we don't need to support these old versions anymore. This
allows some small amount of code cleanup.
Peter Eisentraut [Thu, 16 Jul 2026 09:47:41 +0000 (11:47 +0200)]
Drop support for _MSC_VER less than 1933
Commit aa7c8685234 added a workaround for _MSC_VER less than 1933,
which is Visual Studio 2022 version 17.3. Since we dropped support
for Visual Studio before 2022, and the versions up to 17.3 are long
EOL, we can drop this extra code.
Peter Eisentraut [Thu, 16 Jul 2026 09:47:41 +0000 (11:47 +0200)]
Raise requirement to Visual Studio 2022
The use of _Generic from commit "Replace __builtin_types_compatible_p
with _Generic" causes compiler errors from VS 2019. Apparently, that
compiler is just broken for that (even though it appears to support
_Generic in general, for example in commit 59c2f03d1ec).
Per discussion, just drop support for VS 2019 and require at least VS
2022. This just updates the documentation about that. In passing,
some information about VS 2026 is added.
Check CREATE_REPLICATION_SLOT response shape in libpqwalreceiver
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.
doc: Mention REPACK in MAINTAIN privilege descriptions
REPACK requires the MAINTAIN privilege, but it was omitted from the
lists of commands covered by that privilege in ddl.sgml and the
description of the predefined pg_maintain role in user-manag.sgml.
This was an oversight in commit ac58465e061, which introduced
REPACK.
Add REPACK to both documentation lists, and update the corresponding
comment in aclchk.c.
doc: Fix log_parameter_max_length docs to reference log_min_duration_statement
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.
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.
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.
Bumps XLOG_PAGE_MAGIC.
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
Make VM clear take a RelFileLocator and not fake relcache
This brings it in line with visibilitymap_set(). An upcoming commit will
start reading visibility map buffers with XLogReadBuffer*() functions,
so we no longer require a relation object to pin the visibility map,
allowing us to remove this fake relcache business altogether.
While we're at it, remove a spurious const qualifier from the
RelFileLocator parameter to visibilitymap_set().
Introduce macros for WAL block reference IDs of some heap record types
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.
Include last block in FSM vacuum of bulk extended relation
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.
Jeff Davis [Wed, 15 Jul 2026 19:34:20 +0000 (12:34 -0700)]
Fix like_fixed_prefix_ci() selectivity.
A wrong calculation introduced by 9c8de15969 could cause trailing
characters from the prefix to be passed to like_selectivity() rather
than just the "rest".
Robert Haas [Wed, 15 Jul 2026 17:04:32 +0000 (13:04 -0400)]
Add additional sanity checks when reading a blkreftable.
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
Fix argument names in pg_clear_attribute_stats() errors
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.
Amit Kapila [Wed, 15 Jul 2026 10:10:36 +0000 (15:40 +0530)]
Reject concurrent sequence refreshes.
'ALTER SUBSCRIPTION ... REFRESH SEQUENCES' can race with an already
running sequence synchronization worker. If a second refresh request
resets the synchronization state while the worker has already fetched
sequence values from the publisher but has not yet applied them to the
subscriber, the worker can overwrite the subscriber with stale values
and mark the synchronization as complete.
Avoid this race by rejecting 'ALTER SUBSCRIPTION ... REFRESH SEQUENCES'
when a sequence synchronization worker is already running for the
subscription. The command reports an error asking the user to rerun it
after the current synchronization completes.
Also add a wait for the re-added 'regress_s4' sequence to finish
synchronizing in 036_sequences.pl, so the subsequent test does not race
against its sequencesync worker.
Reported-by: Noah Misch <noah@leadboat.com>
Author: vignesh C <vignesh21@gmail.com> Reviewed-by: Shveta Malik <shveta.malik@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 19, where it was introduced
Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com