Re: bug: virtual generated column can be partition key
jian he <jian.universality@gmail.com>
From: jian he <jian.universality@gmail.com>
To: Fujii Masao <masao.fujii@oss.nttdata.com>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Date: 2025-04-21T09:11:51Z
Lists: pgsql-hackers
Attachments
- v2-0001-virtual-generated-column-can-be-partition-key.patch (text/x-patch) patch v2-0001
On Mon, Apr 21, 2025 at 4:02 PM Fujii Masao <masao.fujii@oss.nttdata.com> wrote:
>
>
>
> On 2025/04/21 11:30, jian he wrote:
> > hi.
> > While trying to make the virtual generated column be part of the partition key,
> > I found this bug.
>
> I haven't looked at the patch in detail yet, but when I applied it
> and ran the regression tests with RELCACHE_FORCE_RELEASE and
> CATCACHE_FORCE_RELEASE enabled, the tests failed with the following diff:
>
> ----------------------------
> ========= Contents of ./src/test/regress/regression.diffs
> diff -U3 /home/runner/work/postgresql/postgresql/src/test/regress/expected/create_table.out /home/runner/work/postgresql/postgresql/src/test/regress/results/create_table.out
> --- /home/runner/work/postgresql/postgresql/src/test/regress/expected/create_table.out 2025-04-21 07:32:03.731119788 +0000
> +++ /home/runner/work/postgresql/postgresql/src/test/regress/results/create_table.out 2025-04-21 07:38:31.358134750 +0000
> @@ -810,8 +810,13 @@
> LINE 1: ...TITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE (c);
> ^
> CREATE TABLE part_c PARTITION OF parted (b WITH OPTIONS NOT NULL DEFAULT 0) FOR VALUES IN ('c') PARTITION BY RANGE ((b));
> +ERROR: cannot use generated column in partition key
> +LINE 1: ...ULL DEFAULT 0) FOR VALUES IN ('c') PARTITION BY RANGE ((b));
> + ^
> +DETAIL: Column "b" is a generated column.
> -- create a level-2 partition
> CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
> +ERROR: relation "part_c" does not exist
> -- check that NOT NULL and default value are inherited correctly
> create table parted_notnull_inh_test (a int default 1, b int not null default 0) partition by list (a);
> create table parted_notnull_inh_test1 partition of parted_notnull_inh_test (a not null, b default 1) for values in (1);
> @@ -871,30 +876,8 @@
>
> -- Both partition bound and partition key in describe output
> \d+ part_c
> - Partitioned table "public.part_c"
> - Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
> ---------+---------+-----------+----------+---------+----------+--------------+-------------
> - a | text | | | | extended | |
> - b | integer | | not null | 0 | plain | |
> -Partition of: parted FOR VALUES IN ('c')
> -Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text))
> -Partition key: RANGE (b)
> -Not-null constraints:
> - "part_c_b_not_null" NOT NULL "b" (local, inherited)
> -Partitions: part_c_1_10 FOR VALUES FROM (1) TO (10)
> -
> -- a level-2 partition's constraint will include the parent's expressions
> \d+ part_c_1_10
> - Table "public.part_c_1_10"
> - Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
> ---------+---------+-----------+----------+---------+----------+--------------+-------------
> - a | text | | | | extended | |
> - b | integer | | not null | 0 | plain | |
> -Partition of: part_c FOR VALUES FROM (1) TO (10)
> -Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text) AND (b IS NOT NULL) AND (b >= 1) AND (b < 10))
> -Not-null constraints:
> - "part_c_b_not_null" NOT NULL "b" (inherited)
> -
> -- Show partition count in the parent's describe output
> -- Tempted to include \d+ output listing partitions with bound info but
> -- output could vary depending on the order in which partition oids are
> @@ -906,7 +889,7 @@
> a | text | | |
> b | integer | | not null | 0
> Partition key: LIST (a)
> -Number of partitions: 3 (Use \d+ to list them.)
> +Number of partitions: 2 (Use \d+ to list them.)
>
> \d hash_parted
> Partitioned table "public.hash_parted"
Thanks for pointing it out.
i think it's related to my silly mistake:
if (TupleDescAttr(RelationGetDescr(rel),
var->varattno)->attgenerated)
should be
if (TupleDescAttr(RelationGetDescr(rel), var->varattno
- 1)->attgenerated)
Feel free to test it again.
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Tighten check for generated column in partition key expression
- 7f239c72a897 13.23 landed
- 04345d7a423a 14.20 landed
- 643a5e96c788 15.15 landed
- 7180d56c5609 16.11 landed
- 0b44f2443f69 17.7 landed
- ba99c9491c44 18.1 landed
- 040cc5f3c782 19 (unreleased) landed
-
Stamp 18beta1.
- caa76b91a606 18.0 cited