Re: Partition pruning can incorrectly exclude a RANGE default partition

From: Tender Wang <tndrwang(at)gmail(dot)com>
To: Chengpeng Yan <chengpeng_yan(at)outlook(dot)com>
Cc: Jacob Brazeal <jacob(dot)brazeal(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Amit Langote <amitlangote09(at)gmail(dot)com>
Subject: Re: Partition pruning can incorrectly exclude a RANGE default partition
Date: 2026-07-28 07:41:01
Message-ID: CAHewXN=Ho1khxWPJb0K=7Be-1tQZYACTUo7qNicJqgvi32w-xg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Chengpeng Yan <chengpeng_yan(at)outlook(dot)com> 于2026年7月27日周一 22:53写道:
>
> ```diff
> diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
> index e7c318bbcac..48d16ebb4fb 100644
> --- a/src/backend/partitioning/partprune.c
> +++ b/src/backend/partitioning/partprune.c
> @@ -3031,15 +3031,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
> */
> if (nvalues == 0)
> {
> - /* ignore key space not covered by any partitions */
> - if (partindices[minoff] < 0)
> - minoff++;
> - if (partindices[maxoff] < 0)
> - maxoff--;
> -
> result->scan_default = partition_bound_has_default(boundinfo);
> - Assert(partindices[minoff] >= 0 &&
> - partindices[maxoff] >= 0);
> result->bound_offsets = bms_add_range(NULL, minoff, maxoff);
> return result;
> ```

postgres=# create table s2_2 partition of s2 for values from (20) to (30);
CREATE TABLE
postgres=# explain SELECT count(*) FROM s2
WHERE a IS NOT NULL
AND a IN (5, 15);
QUERY PLAN
-----------------------------------------------------------------------------
Aggregate (cost=84.12..84.14 rows=1 width=8)
-> Append (cost=0.00..84.00 rows=50 width=0)
-> Seq Scan on s2_1 (cost=0.00..41.88 rows=25 width=0)
Filter: ((a IS NOT NULL) AND (a = ANY ('{5,15}'::integer[])))
-> Seq Scan on s2_d s2_2 (cost=0.00..41.88 rows=25 width=0)
Filter: ((a IS NOT NULL) AND (a = ANY ('{5,15}'::integer[])))
(6 rows)

The above query is OK.
If the value in the IN clause is larger than the max datum in
boundinfo or lower than the min datum in boundinfo,
per the if (nvalues == 0) logic, the min and max offset will finally
be excluded. So the default partition is pruned.
It seems that the current logic ignores the reported case.

Before this email, I thought that as long as every prune_step is
correct, then the final result is correct.
But that way, there seem to be more places where we should consider
the result->scan_default flag in get_matching_range_bounds().

Your fix seems simpler.
I added Amit to the CC list; the original author seems to be him. He
should know more than I do.

--
Thanks,
Tender Wang

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Yilin Zhang 2026-07-28 07:47:29 Re: Grab bag of smaller OpenSSL fixups
Previous Message Ayush Tiwari 2026-07-28 07:27:08 Re: Prove a NOT IN's left-hand expressions non-nullable from quals