Hi Tender,

> On Jul 27, 2026, at 19:34, Tender Wang <[email protected]> wrote:
> 
> I tried the following:
> 
> diff --git a/src/backend/partitioning/partprune.c
> b/src/backend/partitioning/partprune.c
> index e7c318bbcac..96649580e6f 100644
> --- a/src/backend/partitioning/partprune.c
> +++ b/src/backend/partitioning/partprune.c
> @@ -3170,6 +3170,8 @@ get_matching_range_bounds(PartitionPruneContext 
> *context,
>                                 * end up adding the first bound's
> offset, that is, 0.
>                                 */
>                                result->bound_offsets =
> bms_make_singleton(off + 1);
> +                               if (off == boundinfo->default_index)
> +                                       result->scan_default = true;
>                        }
> 
>                        return result;
> 
> This time all cases in regression passed.
> Any thoughts?
> 
> -- 
> Thanks,
> Tender Wang

Thanks for working on this. I may be missing something, but `off`
indexes range-bound datums while `default_index` is a partition index,
so I am not sure the two can be compared. With that patch I still get a
wrong result:

```sql
CREATE TABLE r (a int) PARTITION BY RANGE (a);
CREATE TABLE r1 PARTITION OF r FOR VALUES FROM (0) TO (10);
CREATE TABLE r2 PARTITION OF r FOR VALUES FROM (20) TO (30);
CREATE TABLE rd PARTITION OF r DEFAULT;
INSERT INTO r VALUES (5), (35);

SELECT count(*) FROM r WHERE a IS NOT NULL AND a IN (5, 35);
```

Here `default_index` is 2 but `off` is 3 for 35, so `scan_default` stays
false, `rd` is pruned and the query returns 1 instead of 2.

I agree with Jacob that the problem is in the `nvalues == 0` path. For
35, the `IN` step keeps a `-1` offset, but the `IS NOT NULL` step
removes that same offset. Their intersection therefore loses 35 and
prunes the default partition. If the `IS NOT NULL` step keeps all
offsets, `get_matching_partitions()` can later turn the surviving `-1`
offset into a default-partition scan:

```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;
```

The reported cases and the example above behave as expected with this,
and `make check` passes.

--
Best regards,
Chengpeng Yan




Reply via email to