Commit graph

64699 commits

Author SHA1 Message Date
Jeff Davis
3ab2abc949 Fix obsolete comment.
Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/20260630012919.78@rfd.leadboat.com
Backpatch-through: 19
2026-07-07 18:19:59 -07:00
Jeff Davis
d34ce773d2 Fix unintentional behavior change from 5a38104b36.
Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/20260630012919.78@rfd.leadboat.com
Backpatch-through: 19
2026-07-07 18:04:33 -07:00
Richard Guo
906b1e4a19 Propagate stadistinct through GROUP BY/DISTINCT in subqueries and CTEs
Previously, examine_simple_variable() would return early when a
subquery or CTE used GROUP BY or DISTINCT.  It could detect uniqueness
for single-column cases, but for multi-column GROUP BY or DISTINCT,
selectivity estimation fell back on 1/DEFAULT_NUM_DISTINCT (1/200).
This produced wildly inaccurate estimates for filters and joins on
such columns, often leading the planner to choose nested loop joins
where hash joins would be far better.  This was a significant factor
in poor TPC-DS benchmark performance.

For DISTINCT or GROUP BY key columns that are simple Vars, we now
recurse into the subquery to obtain the base table's stadistinct,
which remains valid after grouping (the set of distinct values is
preserved).  However, MCV frequencies, histograms, and correlation
data are not valid because GROUP BY and DISTINCT change the frequency
distribution of key columns.  So we strip all stats slots from the
copied stats tuple, causing callers like var_eq_const() to use the
1/ndistinct estimate instead.  If stadistinct is stored as a negative
value (a fraction of the base table's row count), we convert it to an
absolute count so it is not misinterpreted relative to the subquery's
output row count.

stanullfrac is adjusted too, since grouping collapses NULLs.  For a
single grouping key, at most one NULL group survives, so the null
fraction is 1/(ndistinct+1).  For multiple grouping keys the null
fraction depends on the joint distribution of the keys, which we don't
have, so we approximate it as zero; NULLs collapse far more
aggressively than non-NULLs, so the real fraction is well below the
base table's, and erring low keeps estimates on the hash-join-favoring
side.

Non-key columns (e.g., aggregate outputs) continue to get no stats,
same as before.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: wenhui qiu <qiuwenhuifx@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49rWYrecgreDhKsfx3VSDW=qo35s+iAmgGu=wpARrM8_g@mail.gmail.com
2026-07-08 09:38:31 +09:00
Fujii Masao
0237f1480a doc: Fix typo in rule-system view example
Commit dcb0049523 accidentally changed the final expanded query's
condition to > 2 while rewriting the example into SQL operator notation.

The original query and the preceding rewritten forms all use >= 2,
and view expansion should preserve that qualification. This commit
changes the final condition from > 2 to >= 2.

Backpatch to all supported versions.

Reported-by: Yaroslav Saburov <y.saburov@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/178248467618.108999.9966122434342474006@wrigleys.postgresql.org
Backpatch-through: 14
2026-07-08 09:04:31 +09:00
Richard Guo
96ab9a990e Fix EXPLAIN failure when deparsing SQL/JSON aggregates
If an expression containing an aggregate is evaluated above the plan
node that computes the aggregate, as happens with window functions or
with expressions postponed to above the final sort, setrefs.c replaces
the Aggref or WindowFunc with a Var referencing the lower node's
output.  For SQL/JSON aggregates such as JSON_ARRAYAGG and
JSON_OBJECTAGG, deparsing the containing JsonConstructorExpr then
failed with "invalid JsonConstructorExpr underlying node type", since
get_json_agg_constructor() did not expect a Var there.

Fix by resolving the Var back to the underlying Aggref or WindowFunc
and deparsing the constructor as if the aggregate were computed at the
current node.  The JsonConstructorExpr retains the RETURNING clause
and the ABSENT/NULL ON NULL and WITH UNIQUE options, and the arguments
come from the resolved aggregate, so the original JSON aggregate
syntax is reproduced in full.  This mirrors how get_agg_expr() already
looks through such a Var when deparsing a combining aggregate.

Reported-by: Thom Brown <thom@linux.com>
Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAA-aLv5QYTaMOk=Qhv6cgwceeHETZV8YJvWZ_rH+yVZCuchATA@mail.gmail.com
Backpatch-through: 16
2026-07-08 08:46:43 +09:00
Jeff Davis
07211f64ac unicode_case.c: change API to signal UTF8 decoding error.
Errors at this point are not expected, but if encountered, signal to
the caller so it can raise the appropriate error.

Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/c355354e6c3f4a7aafb047361b73db247260fca0.camel@j-davis.com
2026-07-07 15:34:05 -07:00
Heikki Linnakangas
7258c891d4 Remove unused tuple fetch in speculative completion
heapam_tuple_complete_speculative() fetched a tuple from the slot only
to free it immediately afterwards, without ever using it.

The function only needs slot->tts_tid to complete or abort the
speculative insertion, so remove the unnecessary fetch and pfree().

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Japin Li <japinli@hotmail.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Reviewed-by: Surya Poondla <suryapoondla4@gmail.com>
Discussion: https://www.postgresql.org/message-id/FCB61654-575D-4F08-AA7E-ED462EDE48A7@gmail.com
2026-07-08 01:16:24 +03:00
Jeff Davis
3686936898 pg_unicode_fast: fix final sigma logic.
If the string is preceded only by Case Ignorable characters, don't
consider it to be a final sigma.

In the process, refactor so that the preceding and following
characters are found first, and then the rule is applied, to improve
clarity.

Discussion: https://postgr.es/m/c355354e6c3f4a7aafb047361b73db247260fca0.camel@j-davis.com
Backpatch-through: 18
2026-07-07 14:53:41 -07:00
Heikki Linnakangas
99319edb8f Deduplicate metapage sanity checks in _bt_gettrueroot()
Replace the metapage sanity checks in _bt_gettrueroot() with a call to
_bt_getmeta(), which does exactly the same checks.

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Neil Chen <carpenter.nail.cz@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAEoWx2nisjqs4iC9o4Hu7-Ab767=cMZZzmhBGb8SaQtMMmVqPQ@mail.gmail.com
2026-07-08 00:25:24 +03:00
Jeff Davis
21ffc271d4 unicode_case.c: defend against truncated UTF8.
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/c355354e6c3f4a7aafb047361b73db247260fca0.camel@j-davis.com
Backpatch-through: 17
2026-07-07 13:34:55 -07:00
Heikki Linnakangas
6f7199a124 Cleanup comments/docs around the new shmem request callbacks
Make it explicit in the docs that the shmem initialization callbacks
are called while holding ShmemIndexLock.

Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAExHW5sHs+eSiTDOd14buayc6JbBX=Hm5ssFMBK0Ki9sTGEOuA@mail.gmail.com
Backpatch-through: 19
2026-07-07 22:32:36 +03:00
Heikki Linnakangas
9c9ddf109b Fix gistkillitems for GiST root page
GiST index killitems feature misbehaves for single-page GiST index,
i.e. one that has only a root page. This is caused by the GiST scan's
curBlkno variable not being initialized for the first-to-scan page,
which is the root page.  Fix this by moving the initializing of
curBlkno into gistScanPage(), where we also set the related curPageLSN
variable.

Commit 377b7ab145 actually added a regression test for this already,
but it merely noted that it's not working and memorized the result
where the items were not killed. Now they are, as the test shows.

This has been broken all along, but since it's just a very minor
performance issue on tiny tables, I didn't bother backpatching it.

Author: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Reviewed-by: Soumya S Murali <soumyamurali.work@gmail.com>
Discussion: https://postgr.es/m/CALdSSPgZWX_D8%2BFx4YQqRN5eW5iSx_rJdqQhCfdWTvqKXVfJ4w%40mail.gmail.com
Discussion: https://postgr.es/m/lxzj26ga6ippdeunz6kuncectr5gfuugmm2ry22qu6hcx6oid6@lzx3sjsqhmt6
2026-07-07 21:21:16 +03:00
Heikki Linnakangas
650bb73c13 Rename register_unlink_segment() to register_unlink_tombstone()
Only "tombstone" files (first segment of main fork) are unlinked after
checkpoints, so rename the function and remove the extra arguments to
make that more clear.

Additionally, add an assertion in mdunlinkfiletag() that the FileTag
only contains expected values.

Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reviewed-by: Thomas Munro <thomas.munro@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAEze2WjfP95SL_Hsu7GzYXLnQyEsT49zOnNvbY_mBLCFiQra1g@mail.gmail.com
2026-07-07 20:05:56 +03:00
Noah Misch
592de8bd21 Fix pg_dump ACL minimization for PROPERTY GRAPH.
Adding a GRANT caused pg_dump to emit a useless REVOKE + GRANT of owner
privileges, as seen in a dump of the regression database:

  REVOKE ALL ON PROPERTY GRAPH graph_rls_schema.cabinet FROM nm;
  GRANT ALL ON PROPERTY GRAPH graph_rls_schema.cabinet TO nm;
  GRANT ALL ON PROPERTY GRAPH graph_rls_schema.cabinet TO PUBLIC;

For normal dumps, this has no functional consequences.  For --no-owner
restores, the extra statements may fail or locate unrelated users of the
destination cluster.

The problem was pg_dump assuming NULL relacl implies acldefault('r'),
the default for TABLE.  Fix by teaching acldefault() to retrieve the
PROPERTY GRAPH default ACL.  So pg_dump can still dump from 19beta1, use
acldefault('g') for v20+ only.  For v19, use a hard-coded snapshot of
the v19 default.

information_schema.pg_property_graph_privileges also misused
acldefault('r'), but its "c.prtype IN ('SELECT')" predicate compensated
for it.  Switch to the new acldefault('g') for clarity.  Bump catversion
since a new view won't work with old binaries.  Back-patch to v19, which
introduced PROPERTY GRAPH.

Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/20260630023308.c7.noahmisch@microsoft.com
Backpatch-through: 19
2026-07-07 09:51:04 -07:00
Nathan Bossart
b34fd845e0 Remove unnecessary volatile qualifiers.
This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block, but the
PG_TRY has since been removed.

Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/akQ5eJR1tCCXme8e%40nathan
2026-07-07 10:57:48 -05:00
Heikki Linnakangas
343594a26d libpq: Drain all pending bytes from SSL/GSS during pqReadData()
The previous commit strengthened a workaround for a hang when large
messages are split across TLS records/GSS tokens. Because that
workaround is implemented in libpq internals, it can only help us when
libpq itself is polling on the socket. In nonblocking situations,
where the client above libpq is expected to poll, the same bugs can
show up.

As a contrived example, consider a large protocol-2.0 error coming
back from a server during PQconnectPoll(), split in an odd way across
two records:

    -- TLS record (8192-byte payload) --
    EEEE[...repeated a total of 8192 times]
    -- TLS record (8193-byte payload) --
    EEEE[...repeated a total of 8192 times]\0

The first record will fill the first half of the libpq receive buffer,
which is 16k long by default. The second record completely fills the
last half with its first 8192 bytes, leaving the terminating NULL in
the OpenSSL buffer. Since we still haven't seen the terminator at our
level, PQconnectPoll() will return PGRES_POLLING_READING, expecting to
come back when the server has sent "the rest" of the data.  But there
is nothing left to read from the socket; OpenSSL had to pull all of
the data in the 8193-byte record off of the wire to decrypt it.

A real server would probably not split up the records this way, nor
keep the connection open after sending a fatal connection error. But
servers that regularly use larger TLS records can get the libpq
receive buffer into the same state if DataRows are big enough, as
reported on the list. While the PostgreSQL server doesn't use larger
TLS records like that, other non-PostgreSQL servers that implement the
wire protocol are known to do that, as well as proxies that sit
between the server and the client

This is a layering violation. libpq makes decisions based on data in
the application buffer, above the transport buffer (whether SSL or
GSS), but clients are polling the socket below the transport buffer.
One way to fix this in a backportable way, without changing APIs too
much, is to ensure data never stays in the transport buffer. Then
pqReadData's postconditions will look similar for both raw sockets and
SSL/GSS: any available data is either in the application buffer, or
still on the socket.

Building on the prior commit, make pqReadData() to drain all pending
data from the transport layer into conn->inBuffer, expanding the
buffer as necessary. This is not particularly efficient from an
architectural perspective (the pqsecure_read() implementations take
care to fit their packets into the current buffer, and that effort is
now completely discarded), but it's hopefully easier to reason about
than a full rewrite would be for the back branches.

Author: Jacob Champion <jacob.champion@enterprisedb.com>
Reviewed-by: Mark Dilger <mark.dilger@enterprisedb.com>
Reviewed-by: solai v <solai.cdac@gmail.com>
Reported-by: Lars Kanis <lars@greiz-reinsdorf.de>
Discussion: https://postgr.es/m/2039ac58-d3e0-434b-ac1a-2a987f3b4cb1%40greiz-reinsdorf.de
Backpatch-through: 14
2026-07-07 18:45:37 +03:00
Heikki Linnakangas
ffd080d94f libpq: Extend "read pending" check from SSL to GSS
An extra check for pending bytes in the SSL layer has been part of
pqReadReady() for a very long time (79ff2e96d). But when GSS transport
encryption was added, it didn't receive the same treatment. (As
79ff2e96d notes, "The bug that I fixed in this patch is exceptionally
hard to reproduce reliably.")

Without that check, it's possible to hit a hang in gssencmode, if the
server splits a large libpq message such that the final message in a
streamed response is part of the same wrapped token as the split
message:

    DataRowDataRowDataRowDataRowDataRowData
    -- token boundary --
    RowDataRowCommandCompleteReadyForQuery

If the split message takes up enough memory to nearly fill libpq's
receive buffer, libpq may return from pqReadData() before the later
messages are pulled out of the PqGSSRecvBuffer. Without additional
socket activity from the server, pqReadReady() (via pqSocketCheck())
will never again return true, hanging the connection.

Pull the pending-bytes check into the pqsecure API layer, where both
SSL and GSS now implement it.

Note that this does not fix the root problem! Third party clients of
libpq have no way to call pqsecure_read_is_pending() in their own
polling. This just brings the GSS implementation up to par with the
existing SSL workaround; a broader fix is left to a subsequent commit.

In preparation for the broader fix, this patch already changes the
*_read_pending() functions to return the number of bytes in the buffer
rather than just a boolean. The current callers don't need that, but
the subsequent fix will.

Author: Jacob Champion <jacob.champion@enterprisedb.com>
Discussion: https://postgr.es/m/CAOYmi%2BmpymrgZ76Jre2dx_PwRniS9YZojwH0rZnTuiGHCsj0rA%40mail.gmail.com
Backpatch-through: 14
2026-07-07 18:45:34 +03:00
Daniel Gustafsson
b9df8d5b8e Replace hardcoded mentions of pg_hosts.conf with GUC
Three error messages were using the default file name pg_hosts.conf
and not the variable backing the GUC, which would make logging be
confusing for users who have renamed the file using the GUC.  Fix
by consistently using the HostsFileName variable.

Backpatch down to v19 where serverside SNI was introduced.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Surya Poondla <suryapoondla4@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAN4CZFMARYjQfgyRaCKOXDO=Q91kuKn=pSC02DAOOr23ojhEGQ@mail.gmail.com
Backpatch-through: 19
2026-07-07 17:34:58 +02:00
Heikki Linnakangas
75e201bf95 pg_dump: check for _beginthreadex() failure in parallel dump
ParallelBackupStart() stored _beginthreadex()'s return value as the
worker's thread handle without checking it.  On failure that value is 0,
which would later reach WaitForMultipleObjects() as a null handle, caught
only by an Assert.  The fork() path already calls pg_fatal() when it
fails; do the same for _beginthreadex(), as pgbench does.

Author: Bryan Green <dbryan.green@gmail.com>
Discussion: https://www.postgresql.org/message-id/8c712d76-ecf7-4749-a6d8-dddc01f298ec@gmail.com
Backpatch-through: 14
2026-07-07 18:11:28 +03:00
Daniel Gustafsson
9762809448 doc: Add reference to CREATE PROCEDURE on CREATE FUNCTION
The reference page for CREATE PROCEDURE had a See Also reference to
CREATE FUNCTION, but the inverse was missing.

Author: Jian He <jian.universality@gmail.com>
Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at>
Discussion: https://postgr.es/m/CACJufxFTi3ceVRJqWRr3L8GR5q+ZhPCZw=1aDTaBGS1AugweFw@mail.gmail.com
2026-07-07 15:55:24 +02:00
David Rowley
d007800f02 Fix COUNT's logic for window run condition support
9d9c02ccd added code to allow the executor to stop early when processing
WindowAgg nodes where a monotonic window function starts producing
values that result in a pushed-down qual no longer matching, and will
never match again due to the window function's monotonic properties.

That commit requires a SupportRequestWFuncMonotonic to exist on the
window function and for it to detect when the function is monotonic.  For
COUNT(ANY) and COUNT(*), the support function failed to consider some
cases where the WindowClause used EXCLUDE to exclude certain rows from
being aggregated.  Some WindowClause definitions mean we aggregate rows
that come after the current row, and when processing those rows later,
if we EXCLUDE certain rows, the monotonic property can be broken.
Wrongly treating the COUNT(*) or COUNT(ANY) aggregate as monotonic could
lead to rows being filtered that should not be filtered from the result
set.

Another issue was that the support function for the COUNT aggregate
mistakenly thought that a WindowClause without an ORDER BY meant that
the results would be both monotonically increasing and decreasing, but
that's only true when in RANGE mode, where all rows are peers.

It is possible to support various cases that do have an EXCLUDE clause,
but getting the logic correct for the exact set of cases that are valid
is quite complex and would likely better be left for a future project.

Here, we mostly disable run condition pushdown when there is an EXCLUDE
clause unless the clause is for EXCLUDE CURRENT ROW, uses COUNT(*)
(rather than COUNT(ANY)), and the window aggregate has no FILTER clause.

Bug: #19533
Reported-by: Qifan Liu <imchifan@163.com>
Author: Chengpeng Yan <chengpeng_yan@outlook.com>
Author: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: John Naylor <johncnaylorls@gmail.com>
Discussion: https://postgr.es/m/19533-413a1014e5d0e766@postgresql.org
Backpatch-through: 15
2026-07-07 23:57:45 +12:00
Peter Eisentraut
c22d2f7fd4 Print off_t/pgoff_t consistently as %lld
This was the dominant style already, but some places used %llu
instead.  Since off_t/pgoff_t are signed types, using %lld seems a
better match, and it might handle obscure error conditions with
negative values better.

Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/20ce62fa-47fc-457b-b504-12f3c1651726%40eisentraut.org
2026-07-07 11:50:22 +02:00
Peter Eisentraut
04fc2564fb Don't cast pgoff_t to possibly 32-bit types for output
pgoff_t is most likely a 64-bit integer, so casting it to a 32-bit
type for output could lose data.  In the cases addressed here, the
files cannot actually get that large, so this is only cosmetic and to
set better examples for the future.  (Similar issues that could have
actual practical impact were addressed separately in commit
e8f851d6172.)

In one case, the 32-bit size is baked into the protocol, so here we
add an elog and document this discrepancy.

Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/20ce62fa-47fc-457b-b504-12f3c1651726%40eisentraut.org
2026-07-07 11:45:09 +02:00
Etsuro Fujita
bb4142fb68 postgres_fdw: Report ANALYZE to pgstats after importing statistics.
Commit 28972b6fc should have done this, but didn't.

While at it, remove an extra blank line in fetch_remote_statistics()
introduced by that commit.

Reported-by: Chao Li <lic@highgo.com>
Co-authored-by: Chao Li <lic@highgo.com>
Co-authored-by: Etsuro Fujita <etsuro.fujita@gmail.com>
Discussion: https://postgr.es/m/6ED81190-B398-44C9-A1E9-8EFE4ED183AF%40gmail.com
Backpatch-through: 19
2026-07-07 18:40:00 +09:00
Peter Eisentraut
2ce7458365 Update GROUP BY ALL comments about window functions
When GROUP BY ALL was added in commit ef38a4d975, the SQL standard
working draft was silent on what to do with window functions.  This
has now been fixed in the SQL standard working draft.  Update the
documentation and code comments about that.

Also make the documentation more specific that we are only talking
about aggregate functions referring to the same query level, which is
another thing that has been made more precise in the SQL standard
working draft since.

The PostgreSQL implementation was already doing the right thing for
both aspects, so no functionality changes.

Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/CAHM0NXjz0kDwtzoe-fnHAqPB1qA8_VJN0XAmCgUZ%2BiPnvP5LbA%40mail.gmail.com
2026-07-07 08:47:07 +02:00
Amit Langote
4c75cc7863 Enforce RETURNING typmod on SQL/JSON DEFAULT behavior expressions
transformJsonBehavior() coerced an ON EMPTY / ON ERROR DEFAULT
expression only when its type differed from the RETURNING type's OID.
When the base type matched but the RETURNING type carried a type
modifier (e.g. numeric(4,1) or varchar(3)), the coercion that enforces
the typmod was skipped, so the DEFAULT value could violate the
declared type:

    SELECT JSON_VALUE(jsonb '{}', '$.a'
                      RETURNING numeric(4,1) DEFAULT 99999.999 ON EMPTY);

returned 99999.999, which 99999.999::numeric(4,1) would reject; the
value could even be stored into a numeric(4,1) column, as later
coercions trust its already-correct type label.

Fix by also coercing when the RETURNING type has a typmod, except for
a NULL constant.  coerce_to_target_type() is a no-op when the typmod
already matches.  The matching-OID short-circuit dates to 74c96699be.

Reported-by: Ewan Young <kdbase.hack@gmail.com>
Author: Ewan Young <kdbase.hack@gmail.com>
Discussion: https://postgr.es/m/CAON2xHPO9f4cAmyGn1mQ=VqoS7wN5rz4yOiqudxX78zninZpCw@mail.gmail.com
Backpatch-through: 17
2026-07-07 08:27:32 +09:00
Robert Haas
4c84545067 Use PG_MODULE_MAGIC_EXT in newly introduced modules
We forgot to use the PG_MODULE_MAGIC_EXT in some newly added modules:
pg_plan_advice, pg_stash_advice and the pgrepack output plugin and
instead used the older PG_MODULE_MAGIC macro.

Author: Andreas Karlsson <andreas@proxel.se>
Discussion: http://postgr.es/m/ad7b910c-d145-4120-994d-2e55c456aa75@proxel.se
Backpatch-through: 19
2026-07-06 15:45:58 -04:00
Tom Lane
42b7ff3aae Fix mishandling of leading '\' in nondeterministic LIKE.
The loop in MatchText() processed a leading '\' without regard to
nondeterministic locales, which is problematic if what the '\'
precedes is an ordinary character that should be subject to
nondeterministic matching.  We'd insist on a literal match for it,
which is not right and is not like what happens with a '\' that
follows some ordinary characters.  Worse, we'd then advance the text
and pattern pointers by one byte, so that if the escaped character
is multibyte the next loop iteration would take the nondeterministic
code path starting at a point within the character.  That could very
possibly cause pg_strncoll() to misbehave.

The fix is quite simple: move the stanza that handles '\' down past
the one that handles nondeterminism.  The stanzas for '%' and '_'
are fine where they are, but the '\' stanza is only correct for
deterministic matching.  The logic for nondeterministic cases is
already prepared to do the right things with a '\'.

While here, I replaced tests of "locale && !locale->deterministic"
with a boolean local variable, reasoning that those are in the hot
loop paths so saving a branch and indirect fetch is worth the
trouble.  I also improved a number of related comments.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/391592.1783187986@sss.pgh.pa.us
Backpatch-through: 18
2026-07-06 14:47:58 -04:00
Tom Lane
d6ffcae32a Fix LIKE matching with nondeterministic collations and backslashes.
Commit 85b7efa1c added support for LIKE with nondeterministic
collations, but it included a bug in the de-escaping logic for
literal pattern substrings.  That unconditionally skipped all
backslashes, but when it encounters '\\' it should emit the second
backslash as a de-escaped character.  That led to acting as though
the escaped backslash was not there.

Bug: #19474
Reported-by: Bowen Shi <zxwsbg12138@gmail.com>
Author: Nitin Motiani <nitinmotiani@google.com>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19474-5b86a95f3d9a7ecb@postgresql.org
Discussion: https://postgr.es/m/CAH5HC94yU+K8Gcdy12M5BS8gwD_SXLSHzc9k5tNk7JDnpBiFMA@mail.gmail.com
Backpatch-through: 18
2026-07-06 14:35:21 -04:00
Tom Lane
431896a84e Make PLy_elog() use pg_integer_constant_p().
This macro is supposed to work like ereport().  But when
59c2f03d1 adjusted ereport() to be more MSVC-friendly,
it missed updating this copy of the logic.

Discussion: https://postgr.es/m/754534.1783264708@sss.pgh.pa.us
Backpatch-through: 19
2026-07-06 13:48:42 -04:00
Tom Lane
2d7808e6fc Fix LIKE/regex optimization for indexscan with exact-match pattern.
Commit 85b7efa1c introduced support for LIKE with non-deterministic
collations.  By moving some conditionals around, it accidentally broke
the optimization for converting a LIKE or regex exact-match pattern
to an equality indexqual when the index collation doesn't match the
expression collation.  That should be allowed if the expression
collation is deterministic.  This patch re-introduces the optimization
for that common case.

One important beneficiary of this optimization is the "\d tablename"
command in psql.  Without this fix that will do a seqscan on pg_class
instead of an index point lookup.

Reported-by: Andres Freund <andres@anarazel.de>
Author: Jelte Fennema-Nio <postgres@jeltef.nl>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/DHBQIZX8SZVI.ZX614ZMFL645@jeltef.nl
Backpatch-through: 18
2026-07-06 13:06:24 -04:00
Robert Haas
e8914ec22f Prevent satisfies_hash_partition from crashing with VARIADIC NULL.
Commit f3b0897a12 fixed some
related problems, but overlooked this one. That commit first
appeared in PostgreSQL 11, so back-patch to all supported branches.

Backpatch-through: 14
Discussion: http://postgr.es/m/CA+TgmobsvQw3F+KRYT83=N3teh8D2t-oPR=U06QDZJE3viCJRg@mail.gmail.com
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
2026-07-06 12:51:29 -04:00
Nathan Bossart
763ee7ea00 Remove switch statements in vector8_shift_{left,right}.
In commit ec8719ccbf, I added switch statements with all expected
shift counts to vector8_shift_{left,right} because vshlq_n_u32()
and vshrq_n_u32() require integer literals.  But we can use
vshlq_u32() instead for both cases, which does not require an
integer literal, thereby avoiding the need for the switch
statements.  This compiles to the same machine code on newer
versions of popular compilers.

Reviewed-by: John Naylor <johncnaylorls@gmail.com>
Discussion: https://postgr.es/m/akWxkA-mszMm57cV%40nathan
2026-07-06 11:40:02 -05:00
Heikki Linnakangas
cde6ede713 Add comment to describe the various frontend cancel methods
Author: Jelte Fennema-Nio <postgres@jeltef.nl>
Discussion: https://www.postgresql.org/message-id/DJPAH0WPJV3K.1PYZ8P0QXZVMX@jeltef.nl
2026-07-06 19:11:04 +03:00
Peter Eisentraut
73dfe79fd6 Remove apparent support for SECURITY LABEL ON PROPERTY GRAPH
Commit 2f094e7ac6 added a mention of SECURITY LABEL ON PROPERTY GRAPH
to the SECURITY LABEL reference page, and it added support to psql tab
completion.  However, security labels on property graphs are not
actually supported (per SecLabelSupportsObjectType()).  The syntax
does work, but that is just a result of how gram.y is factored.  We
don't document or tab-complete the syntax of SECURITY LABEL for other
object types that are not actually supported, so it was inconsistent
to do this for property graphs.  Thus, remove this.

Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://www.postgresql.org/message-id/flat/20260704221210.08.noahmisch%40microsoft.com
2026-07-06 12:10:07 +02:00
Peter Eisentraut
e994f956e4 Forbid generated columns in FOR PORTION OF
With virtual generated columns there is no column to assign to, and we
shouldn't assign directly to stored generated columns either.  (Once
we have PERIODs, we will allow a stored generated column here, but we
will assign to its start/end inputs.)

We can't do this in parse analysis, because views haven't yet been
rewritten, so they mask generated columns.

Author: Paul A. Jungwirth <pj@illuminatedcomputing.com>
Discussion: https://www.postgresql.org/message-id/agOOykf2HV26yVfU%40nathan
2026-07-06 09:32:09 +02:00
Richard Guo
44fb59fc60 Fix qual pushdown past grouping with mismatched equivalence
The planner has two optimizations that move a qual clause across a
grouping boundary: subquery_planner transfers HAVING clauses to WHERE
so they can be evaluated before aggregation, and qual_is_pushdown_safe
pushes outer restriction clauses into a subquery past its DISTINCT,
DISTINCT ON, window PARTITION BY, or set-operation grouping layer.
Both produce wrong results when the moved clause's equivalence
relation disagrees with the grouping's, since the clause then filters
rows the grouping would have merged.

The disagreement has two forms.  A type may belong to multiple btree
opfamilies whose equality operators disagree (e.g. record_ops vs
record_image_ops); or the grouping may use a nondeterministic
collation, where comparing the column under a different collation, or
wrapping it in a function or operator, can distinguish values the
collation considers equal.  Because we cannot prove an arbitrary
expression preserves that equality, a grouping column with a
nondeterministic collation is safe to push only as a direct operand of
a comparison under its own collation.

Fix both call sites through a shared walker parameterized by a
callback that maps each Var to the grouping equality operator for its
column (or InvalidOid for non-grouping Vars).  For HAVING, the
callback recovers the SortGroupClause's eqop via the GROUP Var's
varattno, which requires running before flatten_group_exprs while
havingQual still contains GROUP Vars.  For subquery pushdown, the
callback recovers the eqop from subquery->distinctClause, a window's
partitionClause, or any grouping node in the SetOperationStmt tree.
The walker fires only when there is an equivalence boundary to cross,
gated by either the existing UNSAFE_NOTIN_DISTINCTON_CLAUSE and
UNSAFE_NOTIN_PARTITIONBY_CLAUSE flags or by a recursive check for any
grouping node in the set-op tree.

Back-patch to v18 only.  The HAVING half relies on the RTE_GROUP
mechanism introduced in v18 (commit 247dea89f), which is what lets us
identify grouping expressions via GROUP Vars on pre-flatten
havingQual.  Pre-v18 branches lack that machinery, so a back-patch
there would need a different approach.  Given the absence of field
reports of these bugs on back branches, the risk of carrying a
different fix on stable branches is not justified.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Thom Brown <thom@linux.com>
Reviewed-by: Florin Irion <irionr@gmail.com>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Chengpeng Yan <chengpeng_yan@outlook.com>
Discussion: https://postgr.es/m/CAMbWs4-QLZpn3UVOpeG2fOxxhdnkDNMZ_3Zcm3dqJwRAphz68g@mail.gmail.com
Backpatch-through: 18
2026-07-06 16:13:14 +09:00
Michael Paquier
9d1188f298 Emit a warning when io_min_workers exceeds io_max_workers
When io_min_workers is set strictly higher than io_max_workers, the
minimum has no effect since the pool will never grow past
io_max_workers.  Previously this was silently accepted, which could
be confusing for users expecting at least io_min_workers workers to
always be running.

In order to avoid noise in the server logs, the following restrictions
are in place:
- The only process printing the WARNING is the IO worker with ID 0, on
startup and reload, which is we know the only process always running
when using IO workers.
- At reload, the message shows only if one of the bounds has changed.

Note that this commit reuses a log message updated by 7905416eef.

Author: Baji Shaik <baji.pgdev@gmail.com>
Reviewed-by: Tristan Partin <tristan@partin.io>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://postgr.es/m/CA+fm-RO_O7-XThg2qjj=ir35x9nOFbZYu07gttqAbM5T88QB4Q@mail.gmail.com
2026-07-06 11:37:36 +09:00
Michael Paquier
a924407ce0 Improve checks and error messages of pgstat_register_kind()
pgstat_register_kind() did not validate that required callbacks are
set, which could lead to NULL pointer dereferences when trying to
register a stats kind.  This adds a couple of checks:
- Fox fixed-sized kinds, init_shmem_cb, reset_all_cb, and snapshot_cb
are required.
- For variable-sized kinds, flush_pending_cb is called when there is
pending data, pending_size being required.

These issues should be easy to notice for someone developing an
extension that relies on the custom pgstats APIs.  No backpatch is done
as it is mainly a life improvement.

Author: Sami Imseih <samimseih@gmail.com>
Discussion: https://postgr.es/m/CAA5RZ0uNoe=xT7QsU1K0mMRg-QAwPtupPWZ2J3weM2PjVL2tiA@mail.gmail.com
2026-07-06 10:49:28 +09:00
Michael Paquier
e939332c6b amcheck: Fix memory leak with gin_index_check()
"prev_tuple" was overwritten with a new tuple coming from
CopyIndexTuple() on each loop, leaking memory for every tuple processed
on entry tree pages.  The function uses a dedicated memory context, but
this could leave unused large areas of memory while processing a large
GIN index, the larger the worse.

Oversight in 14ffaece0f.

Author: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Discussion: https://postgr.es/m/CALdSSPjTS6TYe5=5NfMUBYZyQu5cn=ABL6K5_OZjzGWqnwXeBw@mail.gmail.com
Backpatch-through: 18
2026-07-06 09:32:25 +09:00
Tom Lane
07abbc93ba Fix psql's pager selection for wrapped expanded output.
psql decided whether to use the pager in expanded output without
accounting for possible wrapping of column values.  This could
allow it to not use the pager in cases where it should do so.

To fix, move the IsPagerNeeded decision in print_aligned_vertical()
down until after the wrapped data width is known.  Then, if we're in
wrapped mode, prepare a width_wrap array specifying that width (which,
in vertical mode, is the same for all columns).

This is fixing an omission in 27da1a796, so back-patch to v19
where that came in.

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Erik Wienhold <ewie@ewie.name>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/A44110E7-6A03-4C67-95AD-527192A6C768@gmail.com
Backpatch-through: 19
2026-07-05 18:11:40 -04:00
Tom Lane
9f03dab457 Simplify dxsyn_lexize().
There's no need to create and free a temporary copy of the input,
since str_tolower() is already able to cope with not-certainly-
nul-terminated input.  (Before v18, copying was needed because
this code used lowerstr(), but now we can do without.)

Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19525-b0be8e4eb7dbaf07@postgresql.org
2026-07-05 16:22:40 -04:00
Peter Eisentraut
0e4f0827f6 Fix properties orphaned by dropping a label
AlterPropGraph() cleans up pg_propgraph_property entries that are
orphaned by dropping an element or by dropping properties associated
with an element.  But it did not clean up pg_propgraph_property
entries that are orphaned by dropping labels associated with an
element.  Fix this missing case.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Author: zengman <zengman@halodbtech.com>
Discussion: https://www.postgresql.org/message-id/flat/tencent_76F6ACA2364EAA1E5DBD7A47%40qq.com
2026-07-05 13:51:32 +02:00
Tom Lane
a8c2547eaa Disallow renaming a rule to "_RETURN".
ON SELECT rules must be named "_RETURN", while other kinds of rules
must not be; this ancient restriction is depended on by various client
code.  We successfully enforced this convention in most places, but
ALTER RULE allowed renaming a non-SELECT rule to "_RETURN".  Notably,
that would break dump/restore, since the eventual CREATE RULE command
would reject the name.

While at it, remove DefineQueryRewrite's hack to substitute "_RETURN"
for the convention that was used before 7.3.  We dropped other
server-side code that supported restoring pre-7.3 dumps some time ago
(notably in e58a59975 and nearby commits), but this bit was missed.

Bug: #19543
Reported-by: Adam Pickering <adamkpickering@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19543-461228e77f3b32fc@postgresql.org
Backpatch-through: 14
2026-07-04 11:34:26 -04:00
Peter Eisentraut
e0ff7fd9aa Make property graph object descriptions better translatable
getObjectDescription() currently constructs property graph-related
object descriptions incrementally with appendStringInfo().  This
effectively fixes the word order in English, which makes the messages
difficult to translate naturally into languages such as Japanese.

Author: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/20260528.121622.1662808269492494574.horikyota.ntt%40gmail.com
2026-07-03 23:46:19 +02:00
Tom Lane
b82d69abf6 Remove btree_gist's useless logic for encoding-aware truncation.
gbt_var_node_cp_len() contained logic to ensure that its choice of
a common prefix length didn't truncate away part of a multibyte
character.  However, that was really dead code, because we have not
allowed truncation of text-string data types since ef770cbb6, and
it seems unlikely that that behavior could ever get resurrected.
The code is still reachable via gbt_var_penalty, but for that
usage it hardly matters if we break in the middle of a multibyte
character: we're just calculating a small correction factor that
is arguably bunkum anyway in non-C locales.

Hence, delete said code.  That actually removes all need for
gbtree_vinfo.eml, which allows const-ification of the gbtree_vinfo
structs in which we were changing it, which removes one headache
for future attempts to thread-ify the backend.

(Curiously, all this infrastructure was itself added by ef770cbb6.
Not sure why Teodor didn't see the contradiction.)

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/AH*AvQCYKhQGVvPWi1GiU4oY.8.1781609375063.Hmail.3020001251@tju.edu.cn
2026-07-03 15:31:58 -04:00
Tom Lane
fea9c1884b Tighten up btree_gist's handling of truncated bounds.
Truncating an internal node's upper bound can cause it to compare
less than some values that in fact are included in the represented
leaf page.  So we need a hack to make sure it looks large enough
to include all values that could be on the page.  But there's no
equivalent issue for the lower bound.  The fact that the code did
fuzzy comparisons for the lower bound too seems to be the result of
fuzzy thinking.  Or maybe there was a desire to not assume too much
about what the datatype's comparison rule is; but we've already
fully bought into the premise that internal keys compare like bytea.

Hence, remove the useless check against the key's lower bound in
gbt_var_node_pf_match.  The comparable check in gbt_var_penalty may
also be useless, but I'm not quite sure.  In any case that seems
negligible from a performance standpoint, so I left it alone.

Also, in the strategy cases in gbt_var_consistent that only
require comparisons to the lower bound, there's no need to call
gbt_var_node_pf_match at all.  Refactor that logic by inventing
macros lower_is_below_query and upper_is_above_query to directly
express what we need to test.  I also took this opportunity to flip
all the tests around to be "indexkey OP query" rather than mostly
being the reverse: IMO this makes the code less confusing since the
tests now match the names of the strategies.

Also, in the name of consistency, make gbt_num_consistent look
like that too.  There's no functional change there, but this
should be more readable going forward.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/AH*AvQCYKhQGVvPWi1GiU4oY.8.1781609375063.Hmail.3020001251@tju.edu.cn
2026-07-03 15:25:19 -04:00
Tom Lane
4b808ed77c Sync signatures of gbt_var_consistent() and gbt_num_consistent().
For some odd reason we pass the strategy number to gbt_num_consistent
as "const StrategyNumber *strategy".  There's no reason for that:
it almost certainly costs more at both callers and callee to pass a
pointer than to pass a small integer value.  And it's inconsistent
with gbt_var_consistent(), so fix it.

gbt_var_consistent() had its own infelicity, which was not marking
the input "key" value const.  Fix that too while we're here.

This is primarily cosmetic, so I see no need to backpatch.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/AH*AvQCYKhQGVvPWi1GiU4oY.8.1781609375063.Hmail.3020001251@tju.edu.cn
2026-07-03 14:23:32 -04:00
Álvaro Herrera
5ee9d7c299
REPACK CONCURRENTLY: Initialize the range table more honestly
We were skipping a bunch of things that are mostly unnecessary for
REPACK.  However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table.  Cons up an RTE and install it into the EState.

This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.

The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing.  This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.

Author: Antonin Houska <ah@cybertec.at>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
2026-07-03 20:04:48 +02:00
Tom Lane
eef644e57c Fix btree_gist's NotEqual strategy on internal index pages.
gbt_var_consistent() handled the <> (BtreeGistNotEqual) strategy without
distinguishing leaf from internal pages, unlike every other strategy.
In particular, it tried to apply the datatype-specific f_eq method,
which is completely wrong since internal keys might not have the same
representation as leaf keys.  This led to OOB reads and potentially
crashes, and most likely to wrong query results as well.

On leaf pages we can apply the inverse of what the Equal strategy does.
On internal pages, use a correct implementation of what the previous
code intended: we can descend if the query value equals both bounds,
*so long as the bounds aren't truncated*.  With truncated bounds we
don't quite know the range of what's below, so we must always descend.

Adjust the code in gbt_num_consistent() to look similar, too.  This
fixes a performance buglet in that there's no need to do two comparisons
on a leaf entry, but the main point is just to keep code consistency.

Reported-by: 王跃林 <violin0613@tju.edu.cn>
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/AH*AvQCYKhQGVvPWi1GiU4oY.8.1781609375063.Hmail.3020001251@tju.edu.cn
Backpatch-through: 14
2026-07-03 13:50:14 -04:00