Re: BUG #16840: Rows not found in table partitioned by hash when not all partitions exists

From: Michał Albrycht <michalalbrycht(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: BUG #16840: Rows not found in table partitioned by hash when not all partitions exists
Date: 2021-01-28 08:07:31
Message-ID: CACsoHGCxAJje+s6mZuDmHHmfVk+iUzgJk0+LNWvMMz8vnZS0og@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Thanks for quick bug confirmation and patch. I agree that the way code is
presented here is unlikely to happen on production, but I was experimenting
with a custom, dummy hash function which would guarantee that all rows with
volume_id=1 would go to partition 1, volume_id=2 to partition 2 and so on.

CREATE OR REPLACE FUNCTION partition_custom_bigint_hash(value INT8, seed INT8)
RETURNS INT8 AS $$
-- this number is UINT64CONST(0x49a0f4dd15e5a8e3) from
https://github.com/postgres/postgres/blob/REL_13_STABLE/src/include/common/hashfn.h#L83
<https://doxygen.postgresql.org/hashfn_8h_source.html>
SELECT value - 5305509591434766563;
$$ LANGUAGE SQL IMMUTABLE;

CREATE OPERATOR CLASS partition_custom_bigint_hash_op
FOR TYPE int8
USING hash AS
OPERATOR 1 =,
FUNCTION 2 partition_custom_bigint_hash(int8, int8);

Then adding that operator class to table definition:

CREATE TABLE dir (
id SERIAL,
volume_id BIGINT,
path TEXT
) PARTITION BY HASH (volume_id partition_custom_bigint_hash_op);

Now I'm able to create a partition only when it's needed and I know
which partition should be created for a given volume_id
(partition_number = volume_id % number_of_partitions).

Michał Albrycht

śr., 27 sty 2021 o 23:54 Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> napisał(a):

> I wrote:
> > Hmm, seems to be a case of faulty partition exclusion, because the
> > plan isn't scanning anything:
>
> Here's a proposed patch for this. The core of the problem is confusion
> around the number of entries in the PartitionBoundInfoData.indexes array.
> Each of the three types of partitioning has a different rule for that,
> despite which we were expecting assorted code to know what to do, and
> some places got it wrong for hash --- even hash-specific code :-(
>
> I propose here to solve that by explicitly storing the number of entries
> in PartitionBoundInfoData, and thereby removing the need for partition-
> strategy-independent code to know anything about the rules. I think
> we can get away with that in the back branches by adding "nindexes"
> at the end of the struct. This could break extensions that are
> manufacturing their own PartitionBoundInfoData structs, but it seems
> unlikely that there are any.
>
> Most of the patch just straightforwardly sets or uses the new field.
> Notably, partition_bounds_equal() and partition_bounds_copy() get
> significantly simpler and safer. The actual bug fix is in
> get_matching_hash_bounds() and perform_pruning_combine_step(), where
> "all partitions" needs to be 0 .. nindexes-1 not 0 .. ndatums-1.
> (The reason your example fails is that the OR clause should produce
> "all partitions potentially match", but because of this bug, it's
> producing a bitmask that doesn't include the partition we need.)
>
> regards, tom lane
>
>

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Sergei Kornilov 2021-01-28 08:40:56 Re: BUG #16841: psql -- \d tablename , displays "Error : column c.relhasoids does not exit"
Previous Message PG Bug reporting form 2021-01-28 05:48:48 BUG #16841: psql -- \d tablename , displays "Error : column c.relhasoids does not exit"