Skip to content

Back-port 14.9 - 14.10 part II - #2037

Merged
tuhaihe merged 22 commits into
apache:REL_2_STABLEfrom
reshke:pg_14_9_14_10_part2
Sep 23, 2026
Merged

tuhaihe merged 22 commits into
apache:REL_2_STABLEfrom
reshke:pg_14_9_14_10_part2

Conversation

@reshke

@reshke reshke commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Fixes #ISSUE_Number

What does this PR do?

Type of Change

  • Bug fix (non-breaking change)
  • New feature (non-breaking change)
  • Breaking change (fix or feature with breaking changes)
  • Documentation update

Breaking Changes

Test Plan

  • Unit tests added/updated
  • Integration tests added/updated
  • Passed make installcheck
  • Passed make -C src/test installcheck-cbdb-parallel

Impact

Performance:

User-facing changes:

Dependencies:

Checklist

Additional Context

CI Skip Instructions


tglsfdc and others added 5 commits September 21, 2026 13:38
expandRecordVariable() failed to adjust the parse nesting structure
correctly when recursing to inspect an outer-level Var.  This could
result in assertion failures or core dumps in corner cases.

Likewise, get_name_for_var_field() failed to adjust the deparse
namespace stack correctly when recursing to inspect an outer-level
Var.  In this case the likely result was a "bogus varno" error
while deparsing a view.

Per bug #18077 from Jingzhou Fu.  Back-patch to all supported
branches.

Richard Guo, with some adjustments by me

Discussion: https://postgr.es/m/18077-b9db97c6e0ab45d8@postgresql.org
The comment introduced by commit e7cb7ee was a bit too terse, which
could lead to extensions doing different things within the hook function
than we intend to allow.  Extend the comment to explain what they can do
within the hook function.

Back-patch to all supported branches.

In passing, I rephrased a nearby comment that I recently added to the
back branches.

Reviewed by David Rowley and Andrei Lepikhov.

Discussion: https://postgr.es/m/CAPmGK15SBPA1nr3Aqsdm%2BYyS-ay0Ayo2BRYQ8_A2To9eLqwopQ%40mail.gmail.com
xl_tot_len comes first in a WAL record.  Usually we don't trust it to be
the true length until we've validated the record header.  If the record
header was split across two pages, previously we wouldn't do the
validation until after we'd already tried to allocate enough memory to
hold the record, which was bad because it might actually be garbage
bytes from a recycled WAL file, so we could try to allocate a lot of
memory.  Release 15 made it worse.

Since 70b4f82, we'd at least generate an end-of-WAL condition if the
garbage 4 byte value happened to be > 1GB, but we'd still try to
allocate up to 1GB of memory bogusly otherwise.  That was an
improvement, but unfortunately release 15 tries to allocate another
object before that, so you could get a FATAL error and recovery could
fail.

We can fix both variants of the problem more fundamentally using
pre-existing page-level validation, if we just re-order some logic.

The new order of operations in the split-header case defers all memory
allocation based on xl_tot_len until we've read the following page.  At
that point we know that its first few bytes are not recycled data, by
checking its xlp_pageaddr, and that its xlp_rem_len agrees with
xl_tot_len on the preceding page.  That is strong evidence that
xl_tot_len was truly the start of a record that was logged.

This problem was most likely to occur on a standby, because
walreceiver.c recycles WAL files without zeroing out trailing regions of
each page.  We could fix that too, but it wouldn't protect us from rare
crash scenarios where the trailing zeroes don't make it to disk.

With reliable xl_tot_len validation in place, the ancient policy of
considering malloc failure to indicate corruption at end-of-WAL seems
quite surprising, but changing that is left for later work.

Also included is a new TAP test to exercise various cases of end-of-WAL
detection by writing contrived data into the WAL from Perl.

Back-patch to 12.  We decided not to put this change into the final
release of 11.

Author: Thomas Munro <thomas.munro@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com> (the idea, not the code)
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Sergei Kornilov <sk@zsrv.org>
Reviewed-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/17928-aa92416a70ff44a2%40postgresql.org
'Q' for 64 bit integers turns out not to work on 32 bit Perl, as
revealed by the build farm.  Use 'II' instead, and deal with endianness.

Back-patch to 12, like bae868c.

Discussion: https://postgr.es/m/ZQ4r1vHcryBsSi_V%40paquier.xyz
bae868c removed a check that was still needed.  If you had an
xl_tot_len at the end of a page that was too small for a record header,
but not big enough to span onto the next page, we'd immediately perform
the CRC check using a bogus large length.  Because of arbitrary coding
differences between the CRC implementations on different platforms,
nothing very bad happened on common modern systems.  On systems using
the _sb8.c fallback we could segfault.

Restore that check, add a new assertion and supply a test for that case.
Back-patch to 12, like bae868c.

Tested-by: Tom Lane <tgl@sss.pgh.pa.us>
Tested-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/CA%2BhUKGLCkTT7zYjzOxuLGahBdQ%3DMcF%3Dz5ZvrjSOnW4EDhVjT-g%40mail.gmail.com
@reshke

reshke commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

#1922

@leborchuk

Copy link
Copy Markdown
Contributor

LGTM, but see regression in rowtypes.out - tests also should be fixed

@reshke
reshke force-pushed the pg_14_9_14_10_part2 branch from c56f2cb to bb34ca8 Compare September 21, 2026 16:09
@reshke

reshke commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author
diff -I HINT: -I CONTEXT: -I GP_IGNORE: -U3 /__w/cloudberry/cloudberry/src/test/regress/expected/rowtypes.out /__w/cloudberry/cloudberry/src/test/regress/results/rowtypes.out
--- /__w/cloudberry/cloudberry/src/test/regress/expected/rowtypes.out	2026-09-21 09:38:27.531939392 -0700
+++ /__w/cloudberry/cloudberry/src/test/regress/results/rowtypes.out	2026-09-21 09:38:27.565939474 -0700
@@ -1262,7 +1271,7 @@
    c   
 -------
  (1,2)
-GP_IGNORE:(1 row)
+(1 row)
 
 -- Also check deparsing of such cases
 create view composite_v as

that super tricky

reshke and others added 2 commits September 22, 2026 07:46
The hand-written GP_IGNORE:(16 rows) footer broke atmsort's block
parsing (the (N rows) row-count regexp doesn't match a GP_IGNORE-
prefixed footer), so the explain directive leaked into the following
SELECT block and its (1 row) footer got GP_IGNORE-ified in the
expected file only, producing a bogus -GP_IGNORE:(1 row) / +(1 row)
diff and a failed test. Record the actual server output instead:
the Settings and Optimizer lines are globally ignored by gpdiff,
and the plan is identical with optimizer on or off.
This commit changes the WAL reader routines so as a FATAL for the
backend or exit(FAILURE) for the frontend is triggered if an allocation
for a WAL record decode fails in walreader.c, rather than treating this
case as bogus data, which would be equivalent to the end of WAL.  The
key is to avoid palloc_extended(MCXT_ALLOC_NO_OOM) in walreader.c,
relying on plain palloc() calls.

The previous behavior could make WAL replay finish too early than it
should.  For example, crash recovery finishing earlier may corrupt
clusters because not all the WAL available locally was replayed to
ensure a consistent state.  Out-of-memory failures would show up
randomly depending on the memory pressure on the host, but one simple
case would be to generate a large record, then replay this record after
downsizing a host, as Ethan Mertz originally reported.

This relies on bae868c, as the WAL reader routines now do the
memory allocation required for a record only once its header has been
fully read and validated, making xl_tot_len trustable.  Making the WAL
reader react differently on out-of-memory or bogus record data would
require ABI changes, so this is the safest choice for stable branches.
Also, it is worth noting that 3f1ce97 has been using a plain
palloc() in this code for some time now.

Thanks to Noah Misch and Thomas Munro for the discussion.

Like the other commit, backpatch down to 12, leaving out v11 that will
be EOL'd soon.  The behavior of considering a failed allocation as bogus
data comes originally from 0ffe11a, where the record length
retrieved from its header was not entirely trustable.

Reported-by: Ethan Mertz
Discussion: https://postgr.es/m/ZRKKdI5-RRlta3aF@paquier.xyz
Backpatch-through: 12
(cherry picked from commit 50e4a61)
michaelpq and others added 2 commits September 22, 2026 13:36
The same routine to check if a specific pattern can be found in the
server logs was copied over four different test scripts.  This refactors
the whole to use a single routine located in PostgreSQL::Test::Cluster,
named log_contains, to grab the contents of the server logs and check
for a specific pattern.

On HEAD, the code previously used assumed that slurp_file() could not
handle an undefined offset, setting it to zero, but slurp_file() does
do an extra fseek() before retrieving the log contents only if an offset
is defined.  In two places, the test was retrieving the full log
contents with slurp_file() after calling substr() to apply an offset,
ignoring that slurp_file() would be able to handle that.

Backpatch all the way down to ease the introduction of new tests that
could rely on the new routine.

Author: Vignesh C
Reviewed-by: Andrew Dunstan, Dagfinn Ilmari Mannsåker, Michael Paquier
Discussion: https://postgr.es/m/CALDaNm0YSiLpjCmajwLfidQrFOrLNKPQir7s__PeVvh9U3uoTQ@mail.gmail.com
Backpatch-through: 11
(cherry picked from commit 392ea0c)
Cloudberry writes an extra distributed-commit WAL record after every
statement, so the insert LSN that advance_to_record_splitting_zone()
calibrates ends up 8 bytes further away from the page boundary than in
upstream.  Consequently the bytes of the synthetic record header that
spill over to the next page overwrite xlp_magic with bytes of xl_prev
(BEEF) instead of the zeroed xl_info/xl_rmid (0000).  Any invalid magic
number still proves that the page header is validated before the record
header, so accept any 4-hex magic there.
@reshke
reshke force-pushed the pg_14_9_14_10_part2 branch from 5f9b5f5 to 6b2af20 Compare September 22, 2026 10:38
david-rowley and others added 9 commits September 22, 2026 13:39
get_steps_using_prefix_recurse() incorrectly assumed that it could stop
recursive processing of the 'prefix' list when cur_keyno was one before
the step_lastkeyno.  Since hash partition pruning can prune using IS
NULL quals, and these IS NULL quals are not present in the 'prefix'
list, then that logic could cause more levels of recursion than what is
needed and lead to there being no more items in the 'prefix' list to
process.  This would manifest itself as a crash in some code that
expected the 'start' ListCell not to be NULL.

Here we adjust the logic so that instead of stopping recursion at 1 key
before the step_lastkeyno, we just look at the llast(prefix) item and
ensure we only recursively process up until just before whichever the last
key is.  This effectively allows keys to be missing in the 'prefix' list.

This change does mean that step_lastkeyno is no longer needed, so we
remove that from the static functions.  I also spent quite some time
reading this code and testing it to try to convince myself that there
are no other issues.  That resulted in the irresistible temptation of
rewriting some comments, many of which were just not true or inconcise.

Reported-by: Sergei Glukhov
Reviewed-by: Sergei Glukhov, tender wang
Discussion: https://postgr.es/m/2f09ce72-315e-2a33-589a-8519ada8df61@postgrespro.ru
Backpatch-through: 11, where partition pruning was introduced.
(cherry picked from commit 1cf463e)
This could only affect HASH partitioned tables with at least 2 partition
key columns.

If partition pruning was delayed until execution and the query contained
an IS NULL qual on one of the partitioned keys, and some subsequent
partitioned key was being compared to a non-Const, then this could result
in a crash due to the incorrect keyno being used to calculate the
stateidx for the expression evaluation code.

Here we fix this by properly skipping partitioned keys which have a
nullkey set.  Effectively, this must be the same as what's going on
inside perform_pruning_base_step().

Sergei Glukhov also provided a patch, but that's not what's being used
here.

Reported-by: Sergei Glukhov
Reviewed-by: tender wang, Sergei Glukhov
Discussion: https://postgr.es/m/d05b26fa-af54-27e1-f693-6c31590802fa@postgrespro.ru
Backpatch-through: 11, where runtime partition pruning was added.
(cherry picked from commit dd80563)
Under interval_ops, some equal values are distinguishable.  One such
pair is '24:00:00' and '1 day'.  With that being so, btequalimage()
breaches the documented contract for the "equalimage" btree support
function.  This can cause incorrect results from index-only scans.
Users should REINDEX any btree indexes having interval-type columns.
After updating, pg_amcheck will report an error for almost all such
indexes.  This fix makes interval_ops simply omit the support function,
like numeric_ops does.  Back-pack to v13, where btequalimage() first
appeared.  In back branches, for the benefit of old catalog content,
btequalimage() code will return false for type "interval".  Going
forward, back-branch initdb will include the catalog change.

Reviewed by Peter Geoghegan.

Discussion: https://postgr.es/m/20231011013317.22.nmisch@google.com
(cherry picked from commit 0d17fda)
When an UPDATE/DELETE/MERGE's target table is an old-style
inheritance tree, it's possible for the parent to get excluded
from the plan while some children are not.  (I believe this is
only possible if we can prove that a CHECK ... NO INHERIT
constraint on the parent contradicts the query WHERE clause,
so it's a very unusual case.)  In such a case, ExecInitModifyTable
mistakenly concluded that the first surviving child is the target
table, leading to at least two bugs:

1. The wrong table's statement-level triggers would get fired.

2. In v16 and up, it was possible to fail with "invalid perminfoindex
0 in RTE with relid nnnn" due to the child RTE not having permissions
data included in the query plan.  This was hard to reproduce reliably
because it did not occur unless the update triggered some non-HOT
index updates.

In v14 and up, this is easy to fix by defining ModifyTable.rootRelation
to be the parent RTE in plain inheritance as well as partitioned cases.

While the wrong-triggers bug also appears in older branches, the
relevant code in both the planner and executor is quite a bit
different, so it would take a good deal of effort to develop and
test a suitable patch.  Given the lack of field complaints about the
trigger issue, I'll desist for now.  (Patching v11 for this seems
unwise anyway, given that it will have no more releases after next
month.)

Per bug #18147 from Hans Buschmann.

Amit Langote and Tom Lane

Discussion: https://postgr.es/m/18147-6fc796538913ee88@postgresql.org
(cherry picked from commit f752045)
When calculating distances for timestamp values for BRIN minmax-multi
indexes, we need to be careful about overflows for extreme values. If
the value overflows into a negative value, the index may be inefficient.

The new regression test checks this for the timestamp type by adding a
table with enough values to force range compaction/merging. The values
are close to min/max, which means a risk of overflow.

Fixed by converting the int64 values to double first, before calculating
the distance. This prevents the overflow. We may lose some precision, of
course, but that's good enough. In the worst case we build a slightly
less efficient index, but for large distances this won't matter.

This only affects minmax-multi indexes on timestamp columns, with ranges
containing values sufficiently distant to cause an overflow. That seems
like a fairly rare case in practice.

Backpatch to 14, where minmax-multi indexes were introduced.

Reported-by: Ashutosh Bapat
Reviewed-by: Ashutosh Bapat, Dean Rasheed
Backpatch-through: 14
Discussion: https://postgr.es/m/eef0ea8c-4aaa-8d0d-027f-58b1f35dd170@enterprisedb.com
(cherry picked from commit 31c6714)
When calculating the distance between date values, make sure to subtract
them in the right order, i.e. (larger - smaller).

The distance is used to determine which values to merge, and is expected
to be a positive value. The code unfortunately did the subtraction in
the opposite order, i.e. (smaller - larger), thus producing negative
values and merging values the most distant values first.

The resulting index is correct (i.e. produces correct results), but may
be significantly less efficient. This affects all minmax-multi indexes
on date columns.

Backpatch to 14, where minmax-multi indexes were introduced.

Reported-by: Ashutosh Bapat
Reviewed-by: Ashutosh Bapat, Dean Rasheed
Backpatch-through: 14
Discussion: https://postgr.es/m/eef0ea8c-4aaa-8d0d-027f-58b1f35dd170@enterprisedb.com
(cherry picked from commit a6b1b84)
Make sure that infinite values in date/timestamp columns are treated as
if in infinite distance. Infinite values should not be merged with other
values, leaving them as outliers. The code however returned distance 0
in this case, so that infinite values were merged first. While this does
not break the index (i.e. it still produces correct query results), it
may make it much less efficient.

We don't need explicit handling of infinite date/timestamp values when
calculating distances, because those values are represented as extreme
but regular values (e.g. INT64_MIN/MAX for the timestamp type).

We don't need an exact distance, just a value that is much larger than
distanced between regular values. With the added cast to double values,
we can simply subtract the values.

The regression test queries a value in the "gap" and checks the range
was properly eliminated by the BRIN index.

This only affects minmax-multi indexes on timestamp/date columns with
infinite values, which is not very common in practice. The affected
indexes may need to be rebuilt.

Backpatch to 14, where minmax-multi indexes were introduced.

Reported-by: Ashutosh Bapat
Reviewed-by: Ashutosh Bapat, Dean Rasheed
Backpatch-through: 14
Discussion: https://postgr.es/m/eef0ea8c-4aaa-8d0d-027f-58b1f35dd170@enterprisedb.com
(cherry picked from commit 346e007)
When calculating distance for interval values, the code mostly mimicked
interval_mi, i.e. it built a new interval value for the difference.
That however does not work for sufficiently distant interval values,
when the difference overflows the interval range.

Instead, we can calculate the distance directly, without constructing
the intermediate (and unnecessary) interval value.

Backpatch to 14, where minmax-multi indexes were introduced.

Reported-by: Dean Rasheed
Reviewed-by: Ashutosh Bapat, Dean Rasheed
Backpatch-through: 14
Discussion: https://postgr.es/m/eef0ea8c-4aaa-8d0d-027f-58b1f35dd170@enterprisedb.com
(cherry picked from commit 1487acb)
This prevents false-positive reports about "the first child of leftmost
target page is not leftmost of its level", "block %u is not leftmost"
and "left link/right link pair".  They appeared if amcheck ran before
VACUUM cleaned things, after a cluster exited recovery between the
first-stage and second-stage WAL records of a deletion.  Back-patch to
v11 (all supported versions).

Reviewed by Peter Geoghegan.

Discussion: https://postgr.es/m/20231005025232.c7.nmisch@google.com
(cherry picked from commit 6eb1b29)
@reshke
reshke force-pushed the pg_14_9_14_10_part2 branch 2 times, most recently from 8248855 to fb018d5 Compare September 22, 2026 18:46
Squashed fixups for the partition_pruning/inheritance/amcheck/BRIN
backports: adjust expected outputs for CBDB plans (Gather Motion,
Settings/Optimizer lines), honest row footers instead of hand-written
GP_IGNORE placeholders, opr_sanity for new btequalimage/interval
amproc entries (including singlenode/pax variants), and BRIN
minmax-multi expected fixes.
The test arrived with the amcheck 'interrupted page deletion' backport
using PostgreSQL 16+ module names (PostgreSQL::Test::Cluster/Utils) and
pg_control_init(), which do not exist in this PG14-lineage tree; the
script died at compile time (prove exit code 29, no TAP output).

Port it to PostgresNode/TestLib and size the test values against the
real block size minus INDEX_SIZE_MASK slack so the intended btree leaf
layout (and thus the interrupted page deletion UNLINK record) still
arises on CBDB's 32KB pages. Accept the UNLINK_PAGE_META variant of
the record that this codebase emits.
@reshke
reshke force-pushed the pg_14_9_14_10_part2 branch from fb018d5 to 644e0a1 Compare September 22, 2026 19:53
@tuhaihe

tuhaihe commented Sep 23, 2026

Copy link
Copy Markdown
Member

Reviewed by DeepSeek. FYI.


diff --git a/src/test/regress/expected/brin_multi.out b/src/test/regress/expected/brin_multi.out
@@ -501,14 +501,15 @@ SET enable_seqscan = off;
 -- make sure the ranges were built correctly and 2023-01-01 eliminates all
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_date_test WHERE a = '2023-01-01'::date;
-QUERY PLAN
-___________
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_date_test (actual rows=0 loops=1)
          Recheck Cond: (a = '2023-01-01'::date)
          ->  Bitmap Index Scan on brin_date_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '2023-01-01'::date)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_date_test;
 RESET enable_seqscan;
@@ -521,25 +522,27 @@ CREATE INDEX ON brin_timestamp_test USING brin (a timestamp_minmax_multi_ops) WI
 SET enable_seqscan = off;
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_timestamp_test WHERE a = '2023-01-01'::timestamp;
-QUERY PLAN
-___________
+                                    QUERY PLAN                                     
+-----------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_timestamp_test (actual rows=0 loops=1)
          Recheck Cond: (a = '2023-01-01 00:00:00'::timestamp without time zone)
          ->  Bitmap Index Scan on brin_timestamp_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '2023-01-01 00:00:00'::timestamp without time zone)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_timestamp_test WHERE a = '1900-01-01'::timestamp;
-QUERY PLAN
-___________
+                                    QUERY PLAN                                     
+-----------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_timestamp_test (actual rows=0 loops=1)
          Recheck Cond: (a = '1900-01-01 00:00:00'::timestamp without time zone)
          ->  Bitmap Index Scan on brin_timestamp_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '1900-01-01 00:00:00'::timestamp without time zone)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_timestamp_test;
 RESET enable_seqscan;
@@ -551,23 +554,25 @@ CREATE INDEX ON brin_date_test USING brin (a date_minmax_multi_ops) WITH (pages_
 SET enable_seqscan = off;
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_date_test WHERE a = '2023-01-01'::date;
-QUERY PLAN
-___________
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_date_test (actual rows=0 loops=1)
          Recheck Cond: (a = '2023-01-01'::date)
          ->  Bitmap Index Scan on brin_date_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '2023-01-01'::date)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_date_test WHERE a = '1900-01-01'::date;
-QUERY PLAN
-___________
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_date_test (actual rows=0 loops=1)
          Recheck Cond: (a = '1900-01-01'::date)
          ->  Bitmap Index Scan on brin_date_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '1900-01-01'::date)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_date_test;
 RESET enable_seqscan;
@@ -582,25 +587,27 @@ CREATE INDEX ON brin_interval_test USING brin (a interval_minmax_multi_ops) WITH
 SET enable_seqscan = off;
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_interval_test WHERE a = '-30 years'::interval;
-QUERY PLAN
-___________
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_interval_test (actual rows=0 loops=1)
          Recheck Cond: (a = '@ 30 years ago'::interval)
          ->  Bitmap Index Scan on brin_interval_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '@ 30 years ago'::interval)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_interval_test WHERE a = '30 years'::interval;
-QUERY PLAN
-___________
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_interval_test (actual rows=0 loops=1)
          Recheck Cond: (a = '@ 30 years'::interval)
          ->  Bitmap Index Scan on brin_interval_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '@ 30 years'::interval)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_interval_test;
 RESET enable_seqscan;

The force-parallel suites (ic-cbdb-parallel, ic-orca-parallel) run the
same expected files with force_parallel_mode=enable_parallel GUCs, so
'Parallel Seq Scan' plan nodes and extra plan lines differ from the
normal ic-good runs in:

  - brin_multi.sql: the 8 EXPLAIN (ANALYZE/COSTS OFF) statements of the
    minmax_multi date/timestamp/interval overflow tests,
  - partition_prune.sql: the headerless (\t on) hp_prefix_test explain
    \gexec section, whose output cannot be canonicalized as plan blocks
    by the comparison machinery.

Wrap them in --start_ignore/--end_ignore so all suites skip comparing
the region contents, and refresh the brin_multi expected outputs (both
optimizer variants) to match the real parallel-suite output inside the
ignored regions.
@reshke

reshke commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed by DeepSeek. FYI.

diff --git a/src/test/regress/expected/brin_multi.out b/src/test/regress/expected/brin_multi.out
@@ -501,14 +501,15 @@ SET enable_seqscan = off;
 -- make sure the ranges were built correctly and 2023-01-01 eliminates all
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_date_test WHERE a = '2023-01-01'::date;
-QUERY PLAN
-___________
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_date_test (actual rows=0 loops=1)
          Recheck Cond: (a = '2023-01-01'::date)
          ->  Bitmap Index Scan on brin_date_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '2023-01-01'::date)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_date_test;
 RESET enable_seqscan;
@@ -521,25 +522,27 @@ CREATE INDEX ON brin_timestamp_test USING brin (a timestamp_minmax_multi_ops) WI
 SET enable_seqscan = off;
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_timestamp_test WHERE a = '2023-01-01'::timestamp;
-QUERY PLAN
-___________
+                                    QUERY PLAN                                     
+-----------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_timestamp_test (actual rows=0 loops=1)
          Recheck Cond: (a = '2023-01-01 00:00:00'::timestamp without time zone)
          ->  Bitmap Index Scan on brin_timestamp_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '2023-01-01 00:00:00'::timestamp without time zone)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_timestamp_test WHERE a = '1900-01-01'::timestamp;
-QUERY PLAN
-___________
+                                    QUERY PLAN                                     
+-----------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_timestamp_test (actual rows=0 loops=1)
          Recheck Cond: (a = '1900-01-01 00:00:00'::timestamp without time zone)
          ->  Bitmap Index Scan on brin_timestamp_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '1900-01-01 00:00:00'::timestamp without time zone)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_timestamp_test;
 RESET enable_seqscan;
@@ -551,23 +554,25 @@ CREATE INDEX ON brin_date_test USING brin (a date_minmax_multi_ops) WITH (pages_
 SET enable_seqscan = off;
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_date_test WHERE a = '2023-01-01'::date;
-QUERY PLAN
-___________
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_date_test (actual rows=0 loops=1)
          Recheck Cond: (a = '2023-01-01'::date)
          ->  Bitmap Index Scan on brin_date_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '2023-01-01'::date)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_date_test WHERE a = '1900-01-01'::date;
-QUERY PLAN
-___________
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_date_test (actual rows=0 loops=1)
          Recheck Cond: (a = '1900-01-01'::date)
          ->  Bitmap Index Scan on brin_date_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '1900-01-01'::date)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_date_test;
 RESET enable_seqscan;
@@ -582,25 +587,27 @@ CREATE INDEX ON brin_interval_test USING brin (a interval_minmax_multi_ops) WITH
 SET enable_seqscan = off;
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_interval_test WHERE a = '-30 years'::interval;
-QUERY PLAN
-___________
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_interval_test (actual rows=0 loops=1)
          Recheck Cond: (a = '@ 30 years ago'::interval)
          ->  Bitmap Index Scan on brin_interval_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '@ 30 years ago'::interval)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
 SELECT * FROM brin_interval_test WHERE a = '30 years'::interval;
-QUERY PLAN
-___________
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
  Gather Motion 1:1  (slice1; segments: 1) (actual rows=0 loops=1)
    ->  Bitmap Heap Scan on brin_interval_test (actual rows=0 loops=1)
          Recheck Cond: (a = '@ 30 years'::interval)
          ->  Bitmap Index Scan on brin_interval_test_a_idx (actual rows=0 loops=1)
                Index Cond: (a = '@ 30 years'::interval)
-GP_IGNORE:(6 rows)
+ Optimizer: Postgres query optimizer
+(6 rows)
 
 DROP TABLE brin_interval_test;
 RESET enable_seqscan;

Thank you!

@reshke
reshke requested a review from tuhaihe September 23, 2026 12:00

@tuhaihe tuhaihe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. All tests passed.

@tuhaihe
tuhaihe merged commit 6fb99be into apache:REL_2_STABLE Sep 23, 2026
211 of 213 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants