Обсуждение: negative bitmapset member not allowed Error with partition pruning

Поиск
Список
Период
Сортировка

negative bitmapset member not allowed Error with partition pruning

От
Rajkumar Raghuwanshi
Дата:
Hi,

I am getting "ERROR:  negative bitmapset member not allowed" when enable_partition_pruning set to true with below test case.

[edb@localhost bin]$ ./psql postgres
psql (12devel)
Type "help" for help.

postgres=# SET enable_partition_pruning TO on;
SET
postgres=# CREATE TABLE part (a INT, b INT) PARTITION BY LIST(a);
CREATE TABLE
postgres=# CREATE TABLE part_p1 PARTITION OF part FOR VALUES IN (-2,-1,0,1,2);
CREATE TABLE
postgres=# CREATE TABLE part_p2 PARTITION OF part DEFAULT PARTITION BY RANGE(a);
CREATE TABLE
postgres=# CREATE TABLE part_p2_p1 PARTITION OF part_p2 DEFAULT;
CREATE TABLE
postgres=# INSERT INTO part VALUES (-1,-1),(1,1),(2,NULL),(NULL,-2),(NULL,NULL);
INSERT 0 5
postgres=# EXPLAIN (COSTS OFF)
postgres-# SELECT tableoid::regclass as part, a, b FROM part WHERE a IS NULL ORDER BY 1, 2, 3;
ERROR:  negative bitmapset member not allowed

postgres=# SET enable_partition_pruning TO off;
SET
postgres=# EXPLAIN (COSTS OFF)
SELECT tableoid::regclass as part, a, b FROM part WHERE a IS NULL ORDER BY 1, 2, 3;
                               QUERY PLAN                              
------------------------------------------------------------------------
 Sort
   Sort Key: ((part_p1.tableoid)::regclass), part_p1.a, part_p1.b
   ->  Append
         ->  Seq Scan on part_p1
               Filter: (a IS NULL)
         ->  Seq Scan on part_p2_p1
               Filter: (a IS NULL)
(7 rows)

postgres=#


Thanks & Regards,
Rajkumar Raghuwanshi
QMG, EnterpriseDB Corporation

Re: negative bitmapset member not allowed Error with partition pruning

От
Tom Lane
Дата:
Rajkumar Raghuwanshi <rajkumar.raghuwanshi@enterprisedb.com> writes:
> I am getting "ERROR:  negative bitmapset member not allowed" when
> enable_partition_pruning set to true with below test case.

Confirmed here.  It's failing in perform_pruning_combine_step,
which reaches this:

        result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1);

with boundinfo->ndatums == 0.  It's not clear to me whether that situation
should be impossible or not.  If it is valid, perhaps all we need is
something like

        if (boundinfo->ndatums > 0)
            result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1);
        else
            result->bound_offsets = NULL;

although that then opens the question of whether downstream code is
OK with bound_offsets being empty.

(BTW, I'm not sure that it was wise to design bms_add_range to fail for
empty ranges.  Maybe it'd be better to redefine it as a no-op for
upper < lower?)

            regards, tom lane


Re: negative bitmapset member not allowed Error with partitionpruning

От
Amit Langote
Дата:
On 2018/07/27 1:28, Tom Lane wrote:
> Rajkumar Raghuwanshi <rajkumar.raghuwanshi@enterprisedb.com> writes:
>> I am getting "ERROR:  negative bitmapset member not allowed" when
>> enable_partition_pruning set to true with below test case.

Thanks Rajkumar.

> Confirmed here.  It's failing in perform_pruning_combine_step,
> which reaches this:
> 
>         result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1);
> 
> with boundinfo->ndatums == 0.  It's not clear to me whether that situation
> should be impossible or not.  If it is valid, perhaps all we need is
> something like
> 
>         if (boundinfo->ndatums > 0)
>             result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1);
>         else
>             result->bound_offsets = NULL;
> 
> although that then opens the question of whether downstream code is
> OK with bound_offsets being empty.

Yeah, this seems to be the only possible fix and I checked that downstream
code is fine with bound_offsets being NULL/empty.  Actually, the code
that's concerned with bound offsets is limited to partprune.c, because we
don't propagate bound offsets themselves outside this file.

I found one more place in get_matching_hash_bounds where I thought maybe
it'd be a good idea to add this check (if ndatums > 0), but then realized
that that would become dead code as the upstream code takes care of the 0
hash partitions case.  So, maybe an Assert (ndatums > 0) would be better.

Attached find a patch that does both.

> (BTW, I'm not sure that it was wise to design bms_add_range to fail for
> empty ranges.  Maybe it'd be better to redefine it as a no-op for
> upper < lower?)

FWIW, I was thankful that David those left those checks there, because it
helped expose quite a few bugs when writing this code or perhaps that was
his intention to begin with, but maybe he thinks differently now (?).

Thanks,
Amit

Вложения

Re: negative bitmapset member not allowed Error with partition pruning

От
David Rowley
Дата:
On 27 July 2018 at 13:35, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> On 2018/07/27 1:28, Tom Lane wrote:
>> (BTW, I'm not sure that it was wise to design bms_add_range to fail for
>> empty ranges.  Maybe it'd be better to redefine it as a no-op for
>> upper < lower?)
>
> FWIW, I was thankful that David those left those checks there, because it
> helped expose quite a few bugs when writing this code or perhaps that was
> his intention to begin with, but maybe he thinks differently now (?).

I think it's more useful to keep as a bug catcher, although I do
understand the thinking behind just having it be a no-op.

Partition pruning is complex code so I think additional caution is
warranted. People are more likely to notice the error and complain.
It's likely especially useful with tools like sqlsmith, as I imagine
it does not validate the actual results of queries (does it?). but I'm
pretty sure that the ERROR would get flagged up.

-- 
 David Rowley                   http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services


Re: negative bitmapset member not allowed Error with partition pruning

От
Tom Lane
Дата:
David Rowley <david.rowley@2ndquadrant.com> writes:
> On 27 July 2018 at 13:35, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> On 2018/07/27 1:28, Tom Lane wrote:
>>> (BTW, I'm not sure that it was wise to design bms_add_range to fail for
>>> empty ranges.  Maybe it'd be better to redefine it as a no-op for
>>> upper < lower?)

>> FWIW, I was thankful that David those left those checks there, because it
>> helped expose quite a few bugs when writing this code or perhaps that was
>> his intention to begin with, but maybe he thinks differently now (?).

> I think it's more useful to keep as a bug catcher, although I do
> understand the thinking behind just having it be a no-op.

Well, my thinking is that it helps nobody if call sites have to have
explicit workarounds for a totally-arbitrary refusal to handle edge
cases in the primitive functions.  I do not think that is good software
design.  If you want to have assertions that particular call sites are
specifying nonempty ranges, put those in the call sites where it's
important.  But as-is, this seems like, say, defining foreach() to
blow up on an empty list.

            regards, tom lane


Re: negative bitmapset member not allowed Error with partitionpruning

От
Amit Langote
Дата:
On 2018/07/27 12:14, Tom Lane wrote:
> David Rowley <david.rowley@2ndquadrant.com> writes:
>> On 27 July 2018 at 13:35, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> On 2018/07/27 1:28, Tom Lane wrote:
>>>> (BTW, I'm not sure that it was wise to design bms_add_range to fail for
>>>> empty ranges.  Maybe it'd be better to redefine it as a no-op for
>>>> upper < lower?)
> 
>>> FWIW, I was thankful that David those left those checks there, because it
>>> helped expose quite a few bugs when writing this code or perhaps that was
>>> his intention to begin with, but maybe he thinks differently now (?).
> 
>> I think it's more useful to keep as a bug catcher, although I do
>> understand the thinking behind just having it be a no-op.
> 
> Well, my thinking is that it helps nobody if call sites have to have
> explicit workarounds for a totally-arbitrary refusal to handle edge
> cases in the primitive functions.  I do not think that is good software
> design.  If you want to have assertions that particular call sites are
> specifying nonempty ranges, put those in the call sites where it's
> important.  But as-is, this seems like, say, defining foreach() to
> blow up on an empty list.

How about adding Asserts to that effect in partprune.c and execPartition.c
where they're not present?  These are the only two files where it's
currently being used, given that it was invented only recently and exactly
for use by the new pruning code.  I updated the patch that I posted in the
last email to add those Asserts.

FWIW, I can see at least the guard against < 0 values in number of other
bms_* functions, but I won't be the one to make a call one way or the
other about whether to change bms_add_range() to cope with erroneous inputs.

Thanks,
Amit

Вложения

Re: negative bitmapset member not allowed Error with partition pruning

От
David Rowley
Дата:
On 27 July 2018 at 15:14, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> David Rowley <david.rowley@2ndquadrant.com> writes:
>> On 27 July 2018 at 13:35, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> On 2018/07/27 1:28, Tom Lane wrote:
>>>> (BTW, I'm not sure that it was wise to design bms_add_range to fail for
>>>> empty ranges.  Maybe it'd be better to redefine it as a no-op for
>>>> upper < lower?)
>
>>> FWIW, I was thankful that David those left those checks there, because it
>>> helped expose quite a few bugs when writing this code or perhaps that was
>>> his intention to begin with, but maybe he thinks differently now (?).
>
>> I think it's more useful to keep as a bug catcher, although I do
>> understand the thinking behind just having it be a no-op.
>
> Well, my thinking is that it helps nobody if call sites have to have
> explicit workarounds for a totally-arbitrary refusal to handle edge
> cases in the primitive functions.  I do not think that is good software
> design.  If you want to have assertions that particular call sites are
> specifying nonempty ranges, put those in the call sites where it's
> important.  But as-is, this seems like, say, defining foreach() to
> blow up on an empty list.

Okay, that's a fair point. I agree,  adding Asserts at the current
call sites seems better.


-- 
 David Rowley                   http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services


Re: negative bitmapset member not allowed Error with partitionpruning

От
Alvaro Herrera
Дата:
On 2018-Jul-27, David Rowley wrote:

> On 27 July 2018 at 15:14, Tom Lane <tgl@sss.pgh.pa.us> wrote:

> > Well, my thinking is that it helps nobody if call sites have to have
> > explicit workarounds for a totally-arbitrary refusal to handle edge
> > cases in the primitive functions.  I do not think that is good software
> > design.  If you want to have assertions that particular call sites are
> > specifying nonempty ranges, put those in the call sites where it's
> > important.  But as-is, this seems like, say, defining foreach() to
> > blow up on an empty list.
> 
> Okay, that's a fair point. I agree,  adding Asserts at the current
> call sites seems better.

Given the discussion, I pushed two commits: first, bms_add_range returns
the input bms if the range is empty, also adding Rajkumar's test case,
which I also verified to reproduce the bug, and passes (for me) with the
bms_add_range change.

The second commit includes the proposed asserts, but not the change to
avoid calling bms_add_range when the range is empty.

Thanks!

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services