Re: Unexpected (wrong?) result querying boolean partitioned table with NULL partition - Mailing list pgsql-hackers

From David Rowley
Subject Re: Unexpected (wrong?) result querying boolean partitioned table with NULL partition
Date
Msg-id CAApHDvpkzuwfDZvLiW2=52y9X7txUxcS2-c7zAyaHzaM0AxwKg@mail.gmail.com
Whole thread Raw
In response to Unexpected (wrong?) result querying boolean partitioned table with NULL partition  (David Kimura <david.g.kimura@gmail.com>)
Responses Re: Unexpected (wrong?) result querying boolean partitioned table with NULL partition  (Richard Guo <guofenglinux@gmail.com>)
Re: Unexpected (wrong?) result querying boolean partitioned table with NULL partition  (David Kimura <david.g.kimura@gmail.com>)
Re: Unexpected (wrong?) result querying boolean partitioned table with NULL partition  (David Kimura <david.g.kimura@gmail.com>)
List pgsql-hackers
On Wed, 12 Apr 2023 at 22:13, David Kimura <david.g.kimura@gmail.com> wrote:
> Is it fair to assume that, given the same data, a partitioned table should
> return the same results as a non-partitioned table?

Yes, and also the same as when enable_partition_pruning is set to off.

> CREATE TABLE boolpart (a bool) PARTITION BY LIST (a);
> CREATE TABLE boolpart_default PARTITION OF boolpart default;
> CREATE TABLE boolpart_t PARTITION OF boolpart FOR VALUES IN ('true');
> CREATE TABLE boolpart_f PARTITION OF boolpart FOR VALUES IN ('false');
> INSERT INTO boolpart VALUES (true), (false), (null);
>
> EXPLAIN SELECT * FROM boolpart WHERE a IS NOT true;
>                               QUERY PLAN
> -----------------------------------------------------------------------
>  Seq Scan on boolpart_f boolpart  (cost=0.00..38.10 rows=1405 width=1)
>    Filter: (a IS NOT TRUE)
> (2 rows)
>
> SELECT * FROM boolpart WHERE a IS NOT true;
>  a
> ---
>  f
> (1 row)
>
> Compare that to the result of a non-partitioned table:
>
> CREATE TABLE booltab (a bool);
> INSERT INTO booltab VALUES (true), (false), (null);
>
> EXPLAIN SELECT * FROM booltab WHERE a IS NOT true;
>                         QUERY PLAN
> -----------------------------------------------------------
>  Seq Scan on booltab  (cost=0.00..38.10 rows=1405 width=1)
>    Filter: (a IS NOT TRUE)
> (2 rows)
>
> SELECT * FROM booltab WHERE a IS NOT true;
>  a
> ---
>  f

Ouch.  That's certainly not correct.

> I think the issue has to do with assumptions made about boolean test IS NOT
> inequality logic which is different from inequality of other operators.
> Specifically, "true IS NOT NULL" is not the same as "true<>NULL".

Yeah, that's wrong.

> One idea is to use the negation operator for IS_NOT_(true|false) (i.e.
> BooleanNotEqualOperator instead of BooleanEqualOperator). But besides
> presumably being a more expensive operation, not equal is not part of the btree
> opfamily for bool_ops. So, seems like that won't really fit into the current
> partition pruning framework.

There's already code to effectively handle <> operators. Just the
PartClauseInfo.op_is_ne needs to be set to true.
get_matching_list_bounds() then handles that by taking the inverse of
the partitions matching the equality operator.

Effectively, I think that's the attached patch.

There seems to be a bunch of tests checking this already, all of them
assuming the incorrect plans.

David

Attachment

pgsql-hackers by date:

Previous
From: "Hayato Kuroda (Fujitsu)"
Date:
Subject: RE: pg_upgrade and logical replication
Next
From: Amit Kapila
Date:
Subject: Re: Support logical replication of DDLs