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

65369 Commits

Author SHA1 Message Date
Daniel Gustafsson
227f8ea19a pg_rewind: Check the data checksum states of source and target
pg_rewind installs the source's control file on the target, but every
block it does not copy keeps the target's content.  With checksums
enabled on the target and disabled on the source, the rewound server
claims enabled checksums while the blocks copied from the source have
none, and fails checksum verification as soon as it reads them; in the
worst case every connection attempt dies on an unverifiable catalog
page.

Comparing the control files is not enough.  Replay on the rewound
server resumes from the last common checkpoint and adopts the data
checksum state recorded there, so an offline disable on the source
after the divergence leaves both control files saying "off" while the
rewound server still resumes with verification enabled.  Check the
state carried by the divergence checkpoint as well, which pg_rewind
already reads.

Refuse both cases, and an interrupted online transition on either
side, same as pg_checksums does.  The opposite mismatch, checksums on
the source only, is allowed with a warning: recovery under the backup
label adopts the divergence state, so the rewound server keeps
checksums disabled (or converges through the replayed WAL if the
source enabled them online), and no page can fail verification.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/anwm6UPxoVS41QA2@bdtpg
Backpatch-through: 19
2026-09-14 15:33:01 +02:00
Daniel Gustafsson
3e70c527cc pg_checksums: Refuse interrupted transitions, note change is local
An inprogress-on or inprogress-off control file means an online
transition was cut short, running the offline tool on top of it mixes
two procedures.  Refuse it in every mode, with a hint pointing at the
start-stop cycle (or, on a standby, at letting replication finish)
that resets the state.  Also print that the change applies to one
data directory only, with standby-aware wording, since in a
replication setup the same change must be made on every node.

On a primary, inprogress-on cannot survive a graceful stop: the
checksums launcher resolves it from its exit cleanup, and a crashed
primary is already rejected by the existing "cluster must be shut
down" check.  inprogress-off can, however, it is set by the backend
running pg_disable_data_checksums(), and a fast shutdown arriving
between its two barriers leaves it behind in a cleanly shut down
control file, where the next start-stop cycle resolves it at end of
recovery.  A standby can be stopped with either state, since it has
no launcher and only carries forward whatever state the last replayed
WAL record left it in, with a restartpoint persisting that as-is.
The standby is also the deterministic way to reach the new guard,
which is why the test coverage uses one; the primary window would
need an injection point between the two barriers.

The pg_checksums page said the tool still processes all relation files
regardless of an interrupted online transition; describe the refusal
instead.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/anwm6UPxoVS41QA2@bdtpg
Backpatch-through: 19
2026-09-14 15:32:58 +02:00
Daniel Gustafsson
b52a1c2c8a Do not adopt data checksum state from another node during replay
Offline data checksum changes with pg_checksums are local to one node,
but replay adopted the data checksum state carried by checkpoint record
unconditionally.  After enabling checksums offline on only the primary,
a standby thus started verifying checksums it does not have.  After an
offline change on a standby, the next replayed checkpoint silently
reverted the state.

To fix, make the control file track this node's state alone, and have
replay cross-check the replayed state against it instead of adopting
it, warning once per divergent value and reporting when the states
agree again.  pg_control gains a watermark, normally the end LSN of
the newest XLOG2_CHECKSUMS record the node has written or applied,
and a flag marking that the state was last written by pg_checksums.
Recovery must never overwrite this state with a replayed one.  The
control file is updated when all pages are flushed.  This requires
a PG_CONTROL_VERSION bump.

Recovery from a base backup may be an exception to not adopting: its
control file was copied at an arbitrary moment, so the state carried
by the starting checkpoint is the one the WAL from there on was

Also document the offline procedure for replication setups.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reported-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/anwm6UPxoVS41QA2@bdtpg
Backpatch-through: 19
2026-09-14 15:32:55 +02:00
Alexander Korotkov
a23ab4862c Rename the WAIT FOR command to WAIT in the documentation
The command tag is WAIT, but the reference page called the command
"WAIT FOR" in its title, index entry, psql help name and throughout its
prose, and so did the error messages.  FOR is a noise word that makes the
grammar read like English, exactly as INTO does for INSERT and FROM does
for DELETE; neither of those is part of the command's name.  Settle on
WAIT everywhere the command is named, and keep WAIT FOR LSN wherever the
syntax itself is being shown.

Rename the reference page's id and file name to match, following
cb2c696b1d: v19 is not released, so the URL is not yet baked into a
supported version, and every other page's id matches its title.

Reported-by: Masahiko Sawada sawada.mshk@gmail.com
Author: Xuneng Zhou xunengzhou@gmail.com
Reviewed-by: Alexander Korotkov aekorotkov@gmail.com
Discussion: https://postgr.es/m/CAD21AoBdtiPTbm7T_aNeDON9JpFG9g%3DJDUP4WU-Y8t8_xqvR5Q%40mail.gmail.com
Backpatch-through: 19
2026-09-14 14:49:34 +03:00
Alexander Korotkov
6c44473c2d Fix timeout overflow in WAIT FOR LSN
Commit 447aae13b0 accepted TIMEOUT values up to INT64_MAX
milliseconds, but computing the deadline multiplies by 1000, which
caused an int64 overflow. And the command reported a timeout at once
instead of waiting.

Parse the value as an int instead, which simplifies the code and is
consistent with other timeout values such as the statement_timeout GUC.

The specified values are now rounded to the nearest millisecond, so a
positive timeout below half a millisecond becomes zero and waits
indefinitely.

Backpatch to v19, where the TIMEOUT option was introduced.

Reported-by: ChangAo Chen <cca5507@qq.com>
Author: ChangAo Chen <cca5507@qq.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/tencent_86B83240785807077600A1778566B5C12908@qq.com
Backpatch-through: 19
2026-09-14 14:13:04 +03:00
Etsuro Fujita
3ca4abd60c postgres_fdw: Disable attribute statistics import from pre-9.1 servers.
To import attribute statistics, postgres_fdw sent a query wity COLLATE
"C" to remote servers without checking their version.  Since COLLATE is
only supported since v9.1, this could break the import against older
servers; fix by modifying postgres_fdw to check their version and if
older, fall back to sampling.  (This commit still allows importing only
relation statistics from such an older server.)

Also, expand the documentation to mention that attribute statistics are
stored into the local server without applying the foreign table columns'
n_distinct option.

Oversight in commit 28972b6fc.

Reported-by: Fujii Masao <masao.fujii@gmail.com>
Reported-by: Osama Abdul Qader <osamaabdulqader.cs@gmail.com>
Author: Etsuro Fujita <etsuro.fujita@gmail.com>
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwH8%2BuDTwfohpck9v_9L3nwSWACbmC36JYRyqHd5xQN_OA%40mail.gmail.com
Backpatch-through: 19
2026-09-14 19:00:00 +09:00
Richard Guo
9d0adee876 Don't let JSON constructor coercions block SQL function inlining
contain_context_dependent_node_walker() reports a CaseTestExpr as
context-dependent unless it sits under a simple CaseExpr or the
elemexpr of an ArrayCoerceExpr.  A JsonConstructorExpr whose RETURNING
type requires a coercion also carries a CaseTestExpr placeholder in
that coercion, so any SQL function called with such a constructor as
an argument was refused inlining.

Teach the walker that a CaseTestExpr is expected within the coercion
of a JsonConstructorExpr, the same way it already handles the elemexpr
of an ArrayCoerceExpr.  This is safe now that eval_const_expressions
no longer lets an enclosing simple CASE clobber that placeholder.

Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAMbWs48A=VCFbteTkuCoknO1_0-Cu0aMBT0M07dm7vj1QyixDg@mail.gmail.com
Backpatch-through: 19
2026-09-14 17:04:13 +09:00
Richard Guo
e17df18a81 Fix const-folding of JSON constructors inside a simple CASE
A JSON constructor with a RETURNING clause uses a CaseTestExpr as the
placeholder for its result in the coercion expression.  When such a
constructor appears in a WHEN clause of a simple CASE whose test
expression is a constant, eval_const_expressions substituted that
constant for the placeholder, so the coercion produced the CASE's test
value instead of the constructor's result.  For instance,

    CASE 'x' WHEN JSON_OBJECT('a': 'b' RETURNING text) THEN 1 ELSE 0 END

evaluated to 1.

To fix, keep case_val out of scope while simplifying the coercion, as
is already done for the elemexpr of an ArrayCoerceExpr.

Back-patch to v16, where the SQL/JSON constructor functions were
introduced.

Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAMbWs48A=VCFbteTkuCoknO1_0-Cu0aMBT0M07dm7vj1QyixDg@mail.gmail.com
Backpatch-through: 16
2026-09-14 17:03:41 +09:00
Michael Paquier
92aaf50e23 Fix attribute name of pg_stat_get_backend_subxact()
"subxact_overflowed" maps with the name registered in pg_proc.dat.

Oversight in 10ea0f924a.

Author: Shihao Zhong <zhong950419@gmail.com>
Reviewed-by: Jim Jones <jim.jones@uni-muenster.de>
Discussion: https://postgr.es/m/ef48668c-cf8e-4f4b-bf39-4b3b9fb9b85a@uni-muenster.de
2026-09-14 15:58:08 +09:00
Michael Paquier
4b4b5eae90 doc: Mention REPACK in description of reloption toast_value_type
The value set in toast_value_type does not affect the underlying TOAST
table across rewrites.  VACUUM FULL and CLUSTER were mentioned, but not
REPACK.

Suggested-by: Marcos Pegoraro <marcos@f10.com.br>
Discussion: https://postgr.es/m/CAB-JLwbsYHxo5qdWyj1WbRDhxfxsKqg9Y2=wQ4Xwjm51wsLVPg@mail.gmail.com
2026-09-14 14:12:00 +09:00
Amit Kapila
7056ed4663 Disallow SET UNLOGGED for tables in a publication's EXCEPT clause.
Unlogged tables cannot be replicated, so they can neither be published nor
be named in a publication's EXCEPT clause.  ALTER TABLE ... SET UNLOGGED
checked only whether the table was published, so a table in an EXCEPT
clause could still be made unlogged, leaving a state that CREATE
PUBLICATION would reject and that pg_dump could not restore.

Author: Vignesh C <vignesh21@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Peter Smith <smithpb2250@gmail.com>
Reviewed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
Discussion: https://postgr.es/m/CALDaNm1r2MkGu6h8zgU1Kj1sX-FcMQ7wGTeLSnhx-5joiyXEvg@mail.gmail.com
Backpatch-through: 19, where it was introduced
2026-09-14 09:40:18 +05:30
Richard Guo
e28cf96e93 Fix stale copies of PHVs in subqueries
When a subquery references an output of another subquery that gets
pulled up, and that output must be wrapped in a PlaceHolderVar because
of an intermediate outer join, the PHV expression is pushed down into
the subquery.  That copy is not preprocessed along with the outer
query's expressions, so the two copies can diverge.  This used to be
harmless, but since commit 2ebf25e7d join removal edits the whole
query tree, walking into subqueries, and can trip an assert in
ChangeVarNodes if it removes a rel whose Var survives only in such a
copy.

To fix, preprocess these copies at their owning query level, early in
subquery_planner, before anything can consume them (in particular
before SubLinks are turned into SubPlans).  This covers copies pushed
into both LATERAL subquery RTEs and SubLink subselects, and handles
nested copies innermost-first.  extract_lateral_references no longer
preprocesses the copies it pulls out.

Correspondingly, the subquery's own processing must leave the contents
of an upper-level PHV alone, since the owning level has already
preprocessed them: eval_const_expressions returns such a PHV
unchanged, and flatten_join_alias_vars no longer recurses into it.

Back-patch to v16, as with commit 2ebf25e7d.

Reported-by: Tender Wang <tndrwang@gmail.com>
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAHewXN=kWGAXV537mKtSyBYobGdHhYJVDJJMXXZEmmPWE_zaPw@mail.gmail.com
Backpatch-through: 16
2026-09-14 12:26:05 +09:00
Michael Paquier
1cd8669179 Check that a promoted standby keeps its 8-byte OID counter
The counter reaches a standby through XLOG_NEXTOID and checkpoint
records.  This commit adds a test to move the next OID past the 2^32
limit on a primary and read it back from the promoted standby.  This
reuses the same trick as some of the previous tests, with a pg_resetwal
command setting the next OID to be larger than 2^32, combined with a
check based on pg_control_checkpoint().

This closes a testing gap of cb29861646 regarding the replay of
XLOG_NEXTOID, where this WAL record has been updated to pass down an
Oid8 value.  By default, regression tests would use OIDs way below the
UINT32_MAX limit.

Author: Rui Zhao <zhaorui126@gmail.com>
Discussion: https://postgr.es/m/CAHWVJhGkb1n_QSS4M=PKJD5HHcwK3KXpFwVxoRVLzAG3j+2fhQ@mail.gmail.com
2026-09-14 12:05:29 +09:00
Michael Paquier
4000ab1dec Switch pg_column_toast_chunk_id() return value from oid to oid8
This is required for a follow-up commit that will add support for 8-byte
TOAST values, with this function being changed so as it is able to
support the largest TOAST value type available.

Most of the changes in this commit are in the regression tests that use
pg_column_toast_chunk_id(), that need to use some oid8-ish changes.  The
change is surprisingly not invasive as casts from oid to oid8 are
possible (the opposite cast oid8->oid is not supported).

Bump catalog version.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Greg Burd <greg@burd.me>
Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Yugo Nagata <nagata@sraoss.co.jp>
Discussion: https://postgr.es/m/af19kUjwjhaoUTLn@paquier.xy
2026-09-14 11:02:21 +09:00
Michael Paquier
072d4c4240 Refactor some TOAST value ID code to use Oid8 instead of Oid
This is a mechanical update to change most of the TOAST code paths that
assume TOAST value IDs to be Oid variables to become Oid8 variables,
easing an the introduction of an upcoming patch to allow larger TOAST
values, at 8 bytes.

The areas touched by the change are related to table AM, amcheck and
logical decoding's reorder buffer.  A good chunk of the changes involve
switching printf() markers from %u to OID8_FORMAT.

For the sake of the release notes in terms of compatibility (perhaps
worth mentioning, or not), note that this changes some callback
definitions in the table AM section, upgrading some TOAST callbacks to
use Oid8 instead of Oid when referring to a TOAST value.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Greg Burd <greg@burd.me>
Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Yugo Nagata <nagata@sraoss.co.jp>
Discussion: https://postgr.es/m/af19kUjwjhaoUTLn@paquier.xy
2026-09-14 10:00:31 +09:00
Álvaro Herrera
0c5d626961 Fail REPACK in presence of !indisready indexes
Like VACUUM FULL, non-concurrent REPACK would try to rebuild such
indexes, which can sometimes succeed.  Concurrent REPACK would however
fail.  The inconsistency is not good, so make them both throw an error
quickly to force the user to make a decision on those indexes (most
likely, drop them).

Author: Álvaro Herrera <alvherre@kurilemu.de>
Reported-by: Zsolt Parragi <zsolt.parragi@percona.com>
Suggested-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://postgr.es/m/CAN4CZFO5A3YE0Dd-bn7eKrB20pECO3=U0wKg1z2rO=DxgWJJHQ@mail.gmail.com
2026-09-13 14:06:00 +02:00
Alexander Korotkov
8c7a74c323 Re-read standby LSN after recovery ends
WaitForLSN() samples the current position before checking whether
recovery is still in progress. If recovery reaches the target and ends
between those operations, the promotion path can compare against the
stale sample and incorrectly return NOT_IN_RECOVERY.

Read the position again after observing that recovery has ended, before
deciding whether promotion reached the target.

Author: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/CABPTF7U0gW5%2B-4oL7-qdML-yerZxUb7ku4QXp7JxCYo0qyJ_Tw%40mail.gmail.com
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Backpatch-through: 19
2026-09-12 23:30:03 +03:00
Alexander Korotkov
d61f9c90f2 Wake primary_flush waiters after implicit WAL flushes
XLogWrite() can advance the flush position when it finishes a WAL
segment, even if its caller requested only a write. When this happens
while AdvanceXLInsertBuffer() recycles a buffer, primary_flush waiters
are not notified and can sleep until an unrelated flush or checkpoint.

Track such progress with a process-local pending flag and perform the
wakeup after releasing WAL write and insertion locks, keeping
WaitLSNLock acquisition outside the contended WAL path. Add a
deterministic injection-point test that forces this path and inspects
the registration directly in shared memory.

Author: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/CABPTF7U0gW5%2B-4oL7-qdML-yerZxUb7ku4QXp7JxCYo0qyJ_Tw%40mail.gmail.com
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Backpatch-through: 19
2026-09-12 23:29:46 +03:00
Alexander Korotkov
e0c160c307 Prevent WAIT FOR LSN from deadlocking recovery on held locks
A backend waiting for WAL replay can retain locks acquired by earlier
statements.  If the startup process needs one of those locks, directly or
through another backend, before reaching the target LSN, a deadlock can
arise: startup waits for the backend to release the lock, while the backend
waits for startup to advance replay.  The lock manager records the
backend's held locks, but WAIT FOR LSN does not register its dependency on
replay as a lock wait.  The deadlock detector therefore cannot see the
complete cycle.  With unlimited standby conflict delays and no other
timeout or cancellation, this deadlock can persist indefinitely.

Write and flush waits are restricted as well.  Their positions are floored
by the replay position, so without an active walreceiver the startup
process can be their only source of progress.  If a held lock blocks
replay, these waits can form the same cycle: the backend waits for replay
to advance, while replay waits for the backend to release the lock.

Streaming does advance them independently, but only while WAL keeps
arriving.  If reception stops before the target is reached, a blocked
startup process cannot restart the walreceiver.  It also cannot replay
newer checkpoint records needed to advance restartpoints and recycle WAL,
so continued reception can exhaust available space in pg_wal before the
target is reached.  An active receiver at the start of the wait therefore
does not guarantee that the wait can finish while replay remains blocked.

Reject an unsatisfied standby_replay, standby_write, or standby_flush wait
while recovery is active when the backend already holds a granted
heavyweight lock.  This conservative restriction covers direct
relation-lock cycles and indirect cycles involving advisory locks.  It
also rejects some write and flush waits that an active receiver could
satisfy.  Requests whose target is observed as already reached are exempt
from this check, as are primary_flush requests and requests issued after
recovery has ended.  Existing snapshot and recovery-state checks still
apply.

Report one of the held locks so the user can find it, using the same
description the deadlock report uses.

Add replay-mode tests for relation and advisory locks and for the
already-reached case, and document the restriction along with the
recommended usage pattern.

Author: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/CABPTF7U0gW5%2B-4oL7-qdML-yerZxUb7ku4QXp7JxCYo0qyJ_Tw%40mail.gmail.com
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Backpatch-through: 19
2026-09-12 23:29:30 +03:00
Peter Eisentraut
7a0aa99e51 Revert "Use -isystem for LLVM include directories"
This reverts commit 704ef84ef2.

The configure solution in that commit doesn't work if llvm-config
returns a system directory such as /usr/include.  The resulting
-isystem /usr/include puts the C headers before the C++ headers in the
include file order, which is not supposed to be done and causes
failures.  (Using -I /usr/include doesn't have that problem because it
is handled specially by the compiler.)  Per buildfarm members
hippopotamus and jay.

The meson solution does work because it specifically filters out
system includes.  This logic could theoretically be ported to
configure, but that would be a separate undertaking.
2026-09-12 15:50:08 +02:00
Peter Eisentraut
704ef84ef2 Use -isystem for LLVM include directories
LLVM's headers produce warnings under some of the warning options we
might like to use.  For example, -Wshadow=local reports several
warnings from LLVM's headers when compiling llvmjit_inline.cpp.  To
work around that, add the include directories reported by llvm-config
with -isystem rather than -I, which makes the compiler treat them as
system headers and not report warnings from them.  In meson, this is a
built-in facility of the dependency() function, in configure we
implement it ourselves.

An alternative solution would have been to use "#pragma GCC
system_header", as is already done elsewhere in the tree.  But that
seems less elegant here.  Either, we would have to potentially create
a separate wrapper for each LLVM header, or we would have to route all
LLVM includes through a common header, which would break modularity.

Reviewed-by: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/84b6f128-91f5-480e-8a9e-7d0e8f538cea%40eisentraut.org
2026-09-12 12:40:24 +02:00
Melanie Plageman
512d3e8919 Make on-access pruning pin visibility map before locking heap page
b46e1e54d0 pinned the VM after acquiring a cleanup lock on the heap
page when on-access pruning. This was not correct, as pinning the VM may
require I/O. Pin the VM before acquiring the lock. This could mean
occasional unneeded pinning when the buffer is under contention, but
that should be rare.

Reported-by: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAAKRu_aR6e2mNVo-DNHDUfBE5i0cbE4%3Du%3D_Qi9%2Bv573qiGtBig%40mail.gmail.com
Backpatch-through: 19
2026-09-11 20:39:23 -04:00
Michael Paquier
ce420353fa doc: Fix output column name for pg_stat_get_backend_subxact()
pg_stat_get_backend_subxact()'s second attribute was written as
"subxact_overflow" in the docs, but its name is "subxact_overflowed".
Note that the attribute name is still wrong in the TupleDesc generated
in the function; pg_proc agrees with "overflowed".

Author: Shihao Zhong <zhong950419@gmail.com>
Reviewed-by: Jim Jones <jim.jones@uni-muenster.de>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAGRkXqTBZ+zbVuDC8xGEB6Btj61hsui5H5nGqzFBDyOXc=4bjQ@mail.gmail.com
Backpatch-through: 16
2026-09-12 09:04:00 +09:00
Nathan Bossart
237176b795 Fix option argument lookup in in-tree getopt_long().
The in-tree getopt_long() moves each non-option to the end of argv,
which might put it right where an option's argument lookup expects
to find the argument.  For example, "vacuumdb postgres --jobs"
takes "postgres" as the number of jobs instead of complaining that
--jobs is missing its argument.  To fix, stop the argument lookups
at the start of the moved non-options, which we already track to
know when to stop scanning.

Oversight in commit 411b720343.

Author: Sehrope Sarkuni <sehrope@jackdb.com>
Reviewed-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com
Backpatch-through: 17
2026-09-11 15:18:40 -05:00
Nathan Bossart
61aa17b92e Fix optional-argument handling in in-tree getopt_long().
If a long option that accepts an optional argument is given without
one, optind is advanced twice, and the following argument is
skipped.  For example, "pg_waldump --stats --limit 5" skips --limit
and interprets "5" as a non-option, so the command complains that
it cannot location WAL file "5".  The same path also returns BADARG
when optstring starts with a colon, even though nothing is missing.
To fix, handle optional arguments before the missing-argument code,
which then only needs to deal with required arguments.

This is a bug fix and could be back-patched, but since this issue
went unnoticed for 23 years, I'm not going to bother.

Author: Sehrope Sarkuni <sehrope@jackdb.com>
Reviewed-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com
2026-09-11 14:37:51 -05:00
Masahiko Sawada
3a3524e9ac Fix logical decoding to ignore updates without a new tuple.
REPACK (CONCURRENTLY) suppresses logical decoding of the changes it
applies to the transient heap. For an update, suppression keeps the
tuple data out of the WAL record, but the record itself is still
written, and decoding turned it into a change carrying neither a new
nor an old tuple. An output plugin that asks for the changes made by
heap rewrites therefore outputs an UPDATE with no data at all,
reported under the name of the table being repacked.

Ignore such records, as decoding already does for inserts. Updates on
catalog relations don't carry the new tuple either, so we ignore them
too. For deletes, REPACK sets XLH_DELETE_NO_LOGICAL instead.

Backpatch to v19, where REPACK (CONCURRENTLY) was introduced.

Reported-by: Thom Brown <thom@linux.com>
Reviewed-by: Zhijie Hou (Fujitsu) <houzj.fnst@fujitsu.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/CAA-aLv7L_-dOuHXjLh0Di66dExdOb=uTOzR=jtrqCmV0Wxyd2Q@mail.gmail.com
Backpatch-through: 19
2026-09-11 10:54:23 -07:00
Masahiko Sawada
7164dcb665 Fix heap_update() ignoring TABLE_UPDATE_NO_LOGICAL for TOAST tuples.
Previously, heap_update() honored TABLE_UPDATE_NO_LOGICAL for the main
tuple but passed a hardcoded 0 to the tuple toaster, so the tuples it
wrote to the TOAST relation were logged for decoding anyway. That was
harmless until commit 28d534e2ae gave updates the flag; the insert
path has propagated its own ever since suppression was introduced for
heap rewrites.

REPACK (CONCURRENTLY), the only user of the flag, relies on it to keep
the changes it applies to the transient heap out of the logical
stream. Logical decoding therefore reassembled the TOAST value and
then dereferenced a new tuple that the suppressed record doesn't
carry, crashing the backend. This is reachable only if an output
plugin asks for the changes made by heap rewrites. In core that is
just test_decoding with include-rewrites.

Fix this by passing HEAP_INSERT_NO_LOGICAL down to the tuple toaster
when TABLE_UPDATE_NO_LOGICAL is set.

Backpatch to v19, where REPACK (CONCURRENTLY) was introduced.

Reported-by: Thom Brown <thom@linux.com>
Author: Antonin Houska <ah@cybertec.at>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Zhijie Hou (Fujitsu) <houzj.fnst@fujitsu.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/CAA-aLv7L_-dOuHXjLh0Di66dExdOb=uTOzR=jtrqCmV0Wxyd2Q@mail.gmail.com
Backpatch-through: 19
2026-09-11 10:20:42 -07:00
Peter Eisentraut
6a1c1102c4 pg_ctl: Error out on Windows-only options on other platforms
Several pg_ctl command-line options are used only on Windows, but
pg_ctl accepted them anyway on all platforms but didn't do anything
with them.

This commit changes it to report an error if an option is specified
but the platform doesn't make use of it.  The affected options are -e,
-N, -P, -U.  The option -S already errored out on non-Windows
platforms; the new behavior of the other options is aligned with that.

The --help output already didn't list these options on non-Windows
builds, so the fact that they were accepted silently was already
inconsistent.  The man page already lists them as "Options for
Windows".

Several global variables that were set but then only read on Windows,
are now in #ifdef WIN32 blocks.  This avoids -Wunused-but-set-global
warnings that the new clang 23 enables via -Wall.

Reviewed-by: Andreas Karlsson <andreas@proxel.se>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/eb013f9d-2247-444e-8815-9d17b4ce78e7%40eisentraut.org
2026-09-11 17:52:46 +02:00
Peter Eisentraut
4e108ce790 Remove unused global variables
The new clang 23 has a new warning about set-but-unused
static (internal-linkage) global variables: -Wunused-but-set-global,
which is activated in PostgreSQL builds via -Wall.  This triggers a
few warnings in PostgreSQL code.  This commit removes several such
variables that were either never used or whose last use was removed
some time ago.

Reviewed-by: Andreas Karlsson <andreas@proxel.se>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/eb013f9d-2247-444e-8815-9d17b4ce78e7%40eisentraut.org
2026-09-11 17:52:46 +02:00
Tom Lane
962e0a723a Revert "Don't try to re-order the subcommands of CREATE SCHEMA".
This reverts commit a9c350d9ee.
While that intentionally changed our semantics for CREATE SCHEMA
subcommands, it's being argued that the functionality gain does
not justify potentially-subtle compatibility breakage.  The most
useful bit of functionality gain came from commit 404db8f9e
("Execute foreign key constraints in CREATE SCHEMA at the end"),
which we're keeping because it's required by SQL spec and doesn't
seem to create a compatibility hazard by itself.

This is not an exact revert, partly because we're keeping 404db8f9e,
and partly because I kept the API changes that allowed passing down
a ParseState (which allows providing an error cursor for many of the
errors thrown in CREATE SCHEMA).

Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/20260904180712.cc.noahmisch@microsoft.com
Backpatch-through: 19
2026-09-11 11:38:16 -04:00
Tom Lane
f1920437cd Revert "Support more object types within CREATE SCHEMA".
This reverts commit d516974840,
along with parts of commit 049b742daa
("psql: Tighten heuristics for BEGIN/END within CREATE SCHEMA").

While there's nothing particularly wrong with d51697484 in itself,
it depends on a9c350d9e ("Don't try to re-order the subcommands of
CREATE SCHEMA"), and concerns have been raised that the compatibility
impact of that outweighs the benefit of allowing more object types
within CREATE SCHEMA.

It's not possible to revert 049b742da verbatim, because the
CVE-2026-6464 patches 3045a25ba ("Teach psql to skip in-line COPY
... FROM STDIN data after a failure") and cf754f741 ("Save/restore
more lexer state when skipping text due to \if") depend on
infrastructure it added.  Instead, rip out just the bits specifically
needed to parse CREATE FUNCTION within CREATE SCHEMA.  This results in
lexer code that matches v18-and-earlier as modified by CVE-2026-6464.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/20260904180712.cc.noahmisch@microsoft.com
Backpatch-through: 19
2026-09-11 11:32:16 -04:00
Álvaro Herrera
c1c5d28f4a Disallow REPACK (CONCURRENTLY) when replica identity index is dropped
The replica identity determination was "flawed": it fell back to the
primary key if the marked index was dropped, which is a defensible
choice, but logical decoding has a differing opinion and fails to
provide usable tuple identity data in this case.  "Fix" REPACK by
refusing to use the primary key in that case.

This is arguably broken behavior in RelationGetIndexList, but I'll
refrain from changing that at this stage.

Reported-by: Nathan Bossart <nathandbossart@gmail.com>
Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
Author: Ewan Young <kdbase.hack@gmail.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/apCBRKCH8jwKiaSY@nathan
2026-09-11 13:42:45 +02:00
Amit Kapila
479a931155 Fix crash on UPDATE or DELETE of a partition pending detach.
ALTER TABLE ... DETACH PARTITION ... CONCURRENTLY leaves the partition
marked as detach-pending if its wait is interrupted, and only DETACH
PARTITION ... FINALIZE clears that mark. In that state pg_class still says
relispartition while get_partition_ancestors() already reports nothing,
which RelationBuildPublicationDesc() was not ready for. It took
relispartition to mean that the ancestor list is not empty and asked for
its last element, which is an assertion failure, or a NULL pointer
dereference without assertions. CheckCmdReplicaIdentity() needs the
descriptor for every UPDATE and DELETE of a publishable relation and
builds it on first use, so no publication has to exist for this, and a
plain UPDATE crashes the backend.

Treat such a partition as a standalone table, as after the detach is
finalized. It is then published by FOR ALL TABLES publications, but cannot
be added to an EXCEPT clause until the detach completes, which is now
reported with a hint to run DETACH PARTITION ... FINALIZE.

Oversight in fd366065e0, which added the exclusion.

Author: Mikhail Nikalayeu <mihailnikalayeu@gmail.com>
Author: shveta malik <shveta.malik@gmail.com>
Author: Nisha Moond <nisha.moond412@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed-by: Nisha Moond <nisha.moond412@gmail.com>
Discussion: https://postgr.es/m/CADzfLwWoFPT%2Ba73%3DA%3DbsNWRMZQ98NpBEMgE%3Dt1FS4O4_%3DQVLfA%40mail.gmail.com
Backpatch-through: 19, where it was introduced
2026-09-11 15:21:03 +05:30
Fujii Masao
42ce84f878 psql: Schema-qualify catalogs in ALTER DATABASE RESET completion
The tab-completion query used for ALTER DATABASE ... RESET referenced
pg_db_role_setting and pg_database without schema qualification, so a
same-named relation earlier in search_path could be used instead of the
system catalogs.  This could make psql offer misleading RESET candidates.

Commit dbf5a83d46 schema-qualified the unnest() call in this same query,
but the catalog references were still left unqualified.  Fix that by
referring to pg_catalog.pg_db_role_setting and pg_catalog.pg_database
explicitly.

Backpatch to 18, where the tab-completion for ALTER DATABASE ... RESET
was introduced.

Bug: #19523
Reported-by: Zhou Digoal <digoal@126.com>
Author: Vismay Tiwari <vismay.t@gmail.com>
Reviewed-by: Paul Kim <mok03127@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/19523-424457118202f570@postgresql.org
Discussion: https://postgr.es/m/CALHMmB84qkCgv3QAR78YawgfqQZCxSPkRhppxzU=e6fg8RA+AA@mail.gmail.com
Backpatch-through: 18
2026-09-11 18:14:14 +09:00
Amit Langote
0b0b413292 Fall back to SPI for RI checks with mismatched index collations
The fast path probes using the referenced index's collation. When that
collation differs from the referenced column's, it can reject valid
references or accept invalid ones. Changing the scan key's collation
is not sufficient, since btree navigation must use the ordering under
which the index was built.

Cache index eligibility lazily after locking the referenced table,
reloading the constraint information, and opening the index. Compare
index and column collations using the held relation descriptors, and
fall back to SPI on a mismatch. Also move the btree eligibility check
here, avoiding a lookup of an index that REINDEX CONCURRENTLY could
drop before the referenced-table lock is acquired.

Cache both acceptance and rejection until the constraint information
is reloaded, so subsequent rows need not repeat the comparisons. Check
before probing or buffering any row. If batch entry initialization
rejects the index, remove that entry while preserving any other pending
checks.

Add ICU regression coverage for per-row validation, ordinary inserts,
reordered index columns, both directions of collation mismatch, and
fallback while another foreign key check is pending.

Reported-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/CAA4eK1Lk1DfgiFPL-HccZm-Nm+exg+FcsODH8KPw6BOBuzfHtA@mail.gmail.com
Backpatch-through: 19
2026-09-11 17:48:32 +09:00
Amit Kapila
5624de9904 Validate ALTER PUBLICATION after acquiring the publication lock.
AlterPublicationOptions() can use stale publication state when the
publication is modified concurrently while waiting for the publication
lock. In particular, a concurrent ALTER PUBLICATION ... SET ALL TABLES
can change puballtables, causing the validation to make decisions based
on the old value and leads to assertion failure. Likewise,
CheckAlterPublication() could miss a table added concurrently, letting
SET ALL TABLES EXCEPT (...) leave pg_publication_rel with a mixture of
inclusion and exclusion rows.

Fix by acquiring the lock and re-reading the publication tuple in
AlterPublication() before either path runs, and by calling
CheckAlterPublication() only after that.

Also fix 037_except.pl, which left one computed result untested and
silently reused a subscription created by an earlier test.

Author: Vignesh C <vignesh21@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Discussion: https://postgr.es/m/CALDaNm1r2MkGu6h8zgU1Kj1sX-FcMQ7wGTeLSnhx-5joiyXEvg@mail.gmail.com
Backpatch-through: 19, where it was introduced
2026-09-11 09:51:05 +05:30
Michael Paquier
f33844889b Add relation option toast_value_type
This relation option gives the possibility to define the attribute type
that can be used for chunk_id in a TOAST table when it is initially
created.  An update of this parameter has no effect if a TOAST table
already exists under the relation, even on rewrites.  It cannot be set
for TOAST relations.

This new option can be set only to "oid" as of this commit.  This
feature is extracted as a patch of its own to ease the introduction of a
second mode in a follow-up change, related to the introduction of 8-byte
OIDs in external TOAST pointers.

Bump catalog version, as StdRdOptions has changed.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Greg Burd <greg@burd.me>
Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Yugo Nagata <nagata@sraoss.co.jp>
Discussion: https://postgr.es/m/af19kUjwjhaoUTLn@paquier.xyz
2026-09-11 12:26:58 +09:00
Michael Paquier
1497ea77ed Add static assertion to track the no-padding rule of varatt_external_oid
varatt_external_oid (varatt_external in v19 and older branches) having
no padding is a rule that has been implied for years, as pointers of
this structure may be compared using memcpy().

I doubt that anybody is going to break this rule as varatt_external is
old enough that it could vote in most countries, but this makes varatt.h
more consistent for a follow-up change that introduces a second on-disk
external TOAST pointer, and it's free to have a compile-time rule.

Suggested-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Discussion: https://postgr.es/m/CALj2ACVG9cjxr-0jb8PP_Vb7vJvVGBVM_fQ2srt4CpyURpfYhQ@mail.gmail.com
2026-09-11 10:58:51 +09:00
Michael Paquier
34fcd735f1 Add support for TOAST chunk_id type in binary upgrades
This commit adds a new SQL function able to set the type of a chunk_id
attribute for a TOAST table across binary upgrades.  The value is set
when the creation of a TOAST table is required across upgrades, in the
same fashion as the TOAST relation's oid and relfilenode.

Note that this piece currently works only with a TOAST table's chunk_id
set at OIDOID, because it is currently the only type of on-disk external
TOAST pointer supported.  This change is required for a follow-up
feature that aims to introduce support for 8-byte OIDs in external TOAST
pointers.

Taking care of this issue separately is less code churn for the next
changes, and perhaps some of the surrounding discussions with support
for different types of external on-disk TOAST pointers will find this
new facility useful.

Bump catalog version.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Greg Burd <greg@burd.me>
Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Yugo Nagata <nagata@sraoss.co.jp>
Discussion: https://postgr.es/m/af19kUjwjhaoUTLn@paquier.xyz
2026-09-11 10:54:48 +09:00
Jeff Davis
ba9e747c49 Revert 87b2968df0 and 0a90df58cf.
Those changes were intended to avoid dependencies on the global libc
locale settings by basing identifier casefolding on the default
locale.  They introduced an unintentional behavior difference for the
builtin provider with locale C and a single-byte encoding.

Instead of fixing that edge case, just revert the changes.  The
identifier casefolding behavior has always been based on the global
libc locale, and clients make an effort to use the same rules.  Until
we have a plan to change that, provider-specific identifier
casefolding doesn't make sense.

Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/20260826225510.10.noahmisch@microsoft.com
Backpatch-through: 19
2026-09-10 18:12:48 -07:00
Masahiko Sawada
504fe10d1d Fix misplaced comment in snapbuild.c.
Commits 2bef06d516 and 240e0dbacd added code between the comment and
the assignment it describes, so the comment now appears to explain an
unrelated line. Move it back to its original place.

Author: Antonin Houska <ah@cybertec.at>
Discussion: https://postgr.es/m/14864.1788978951@localhost
2026-09-10 13:33:21 -07:00
Nathan Bossart
8367b63e2c Rename PqMsg_Progress to PqParallelMsg_Progress.
The previous name was considered to be unduly generic.  This commit
addresses that by adding a new "PqParallelMsg" prefix for protocol
characters sent by parallel workers to leader processes.  The new
prefix can be reused for new parallel worker message types added in
the future.

Author: Sami Imseih <samimseih.pg@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Antonin Houska <ah@cybertec.at>
Discussion: https://postgr.es/m/CAN12%2BYLqbiA1v3FPD94yLbXgdyoWxVEY6%3DDtdpTPo9YCRuCpfg%40mail.gmail.com
2026-09-10 15:10:35 -05:00
Robert Haas
3117cf3882 pg_plan_advice: Document interaction with GEQO.
The general nature of this interaction has been understood (at least
by me) since before the original commit, but I failed to explicitly
document it. I also left behind an XXX in the README which I intended
to remove before commit. Fix those things.

Reported-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/CA+TgmoYmXy-jiP5qDhqNEiYFEBzQsArO6O2d9E8szNZqi1bePQ@mail.gmail.com
2026-09-10 13:54:30 -04:00
Robert Haas
f15036f20b pg_plan_advice: pgindent
Oversight in 1129570f65

Reported-by: Nazir Bilal Yavuz <byavuz81@gmail.com> (off-list)
Backpatch-through: 19
2026-09-10 13:46:26 -04:00
Álvaro Herrera
8db08e2522 Rework REPACK's documentation on clustering
Commit ac58465e06 moved the discussion on clustering from CLUSTER's
refpage to REPACK's, but somehow introduced a mistake regarding when
exactly can the seqscan-and-sort strategy be used with respect to btrees
(spoiler: it was 100% backwards).  Fix that, but also restructure and
reword the whole subsection more fully to try and make it more coherent.

Author: Chao Li <li.evan.chao@gmail.com>
Author: Álvaro Herrera <alvherre@kurilemu.de>
Reported-by: Antonin Houska <ah@cybertec.at>
Backpatch-through: 19
Discussion: https://postgr.es/m/69CA7636-0359-42B6-B971-16A036698187@gmail.com
2026-09-10 17:56:39 +02:00
Etsuro Fujita
9f4bd91a19 postgres_fdw: Adjust warning message in statistics import.
The previous warning message when falling back to sampling in a certain
case failed to properly mention the reason for that.

Also, for clarity, rewrite a comment about the fallback and add a note
about it to postgres-fdw.sgml.

Follow-up to commit 6a8571568.

Reported-by: Fujii Masao <masao.fujii@gmail.com>
Author: Etsuro Fujita <etsuro.fujita@gmail.com>
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwHq1VuXwxeDU8N4dd9U4RFEW982qQ9C26mRQDs3nu_Naw%40mail.gmail.com
Backpatch-through: 19
2026-09-10 17:30:00 +09:00
Amit Langote
5e34fe3580 Clarify RI tuple-lock result handling comments
Explain that returning false for TM_SelfModified follows ExecLockRows(),
which skips such tuples. This differs from TM_Updated, which is
unexpected in READ COMMITTED with FIND_LAST_VERSION.

Also remove "fall through to error" from the TM_Updated comment, since
the code calls elog(ERROR) directly.

Reported-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/CAA4eK1Lk1DfgiFPL-HccZm-Nm+exg+FcsODH8KPw6BOBuzfHtA@mail.gmail.com
Backpatch-through: 19
2026-09-10 17:17:16 +09:00
Fujii Masao
bd9d6ffa1a Remove stale comment and redundant assignment in BuildTupleHashTable()
Since commit bf6c614a2f, BuildTupleHashTable() has created the table
slot unconditionally rather than on the first lookup. However, the
comment still described the old behavior, and tableslot was still
redundantly initialized to NULL before being assigned the new slot.

Remove the stale comment and redundant assignment.

Author: Tatsuya Kawata <kawatatatsuya0913@gmail.com>
Reviewed-by: Quan Zongliang <quanzongliang@yeah.net>
Discussion: https://postgr.es/m/CAHza6qfduAcYc3HdXP5DYscNstz0ic6ctHTNH70VL1Uy-nJ6zg@mail.gmail.com
2026-09-10 16:11:38 +09:00
Michael Paquier
3f2f5e7c4c Split transaction data out of pgstats table counters
At backend level, PgStat_TableCounts currently stores all the per-table
pending counters in one structure.  This is now split into two parts,
with the transactional part of the data moved out of PgStat_TableCounts
into its own structure labelled with an "xact" in PgStat_RelationStatus.

While on it, move truncdropped out of the counters and into
PgStat_RelationStatus so as both structs (existing PgStat_TableCounts
and new PgStat_TableCountsXact) contain only counters.  The previous
state was slightly confusing: this flag is a state tracking if a
relation has been truncated at backend-level, and not a counter.

Because truncdropped no longer lives inside PgStat_TableCounts, this
commit teaches the flush callback to treat a pending truncate as
sufficient reason to flush, even when both counter structs are otherwise
all zeros.

This refactoring work is in preparation of a different patch that wants
to introduce the concept of transactional stats data flush.  Compared to
all the other stats kinds, relations are an exception as they mix
transactional and non-transactional data.

Author: Sami Imseih <samimseih.pg@gmail.com>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/aoU32VTkUtpdUewB@paquier.xyz
2026-09-10 13:54:26 +09:00
Amit Langote
3f660d86ba Take RI fast-path snapshot after locking referenced relation
ri_FastPathCheck() acquired its scan snapshot before opening the
referenced relation.  If it then waited for the relation lock in READ
COMMITTED mode, a referenced row committed during the wait would not be
visible to the old snapshot.  The check could consequently report a
foreign key violation even though the referenced row existed.

The batched path acquires its scan snapshot after opening the relations,
so it does not have the lock-wait problem.  The per-row path remains
reachable during constraint validation and checks re-entered from a
batch flush.

Take the snapshot after opening the referenced relation and reloading
the constraint information.  This also agrees with the SPI path, which
acquires the referenced-relation lock before selecting the snapshot
used for the check.

Also make the scan snapshot active for the duration of the check, so
STABLE cast and equality functions use the same snapshot as the index
scan.  Otherwise, a STABLE cast can miss rows inserted by earlier AFTER
triggers and cause a valid foreign key to be rejected.  Add a
regression test comparing this case with the SPI path.

Finally, also advance the command counter after acquiring the
referenced-relation lock and before reloading the constraint
information, so local invalidations are processed under the lock, as in
the SPI path.

Add an injection-point test that pauses a per-row check before locking
the referenced relation, commits the missing referenced row in another
session, and verifies that validation succeeds.  Force per-row
validation by using a role without SELECT privilege on the referenced
table, so the test exercises this path even with batching enabled.

Add isolation-test coverage for the visibility of a referenced row
committed after the referencing transaction has executed an earlier
command.  A later command can see such a row in READ COMMITTED, but not
in REPEATABLE READ or SERIALIZABLE.

Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/CA+HiwqEhm+_=bs=2wavAJz-UqC+1KebD31++mapJQQGweE8iQQ@mail.gmail.com
Backpatch-through: 19
2026-09-10 13:34:37 +09:00