Skip to content

Commit cdde886

Browse files
committed
Fix crash when using partition bound expressions
Since 7c079d7, partition bounds are able to use generalized expression syntax when processed, treating "minvalue" and "maxvalue" as specific cases as they get passed down for transformation as a column references. The checks for infinite bounds in range expressions have been lax though, causing crashes when trying to use column reference names with more than one field. Here is an example causing a crash: CREATE TABLE list_parted (a int) PARTITION BY LIST (a); CREATE TABLE part_list_crash PARTITION OF list_parted FOR VALUES IN (somename.somename); Note that the creation of the second relation should fail as partition bounds cannot have column references in their expressions, so when finding an expression which does not match the expected infinite bounds, then this commit lets the generic transformation machinery check after it. The error message generated in this case references as well a missing RTE, which is confusing. This problem will be treated separately as it impacts as well default expressions for some time, and for now only the cases where a crash can happen are fixed. While on it, extend the set of regression tests in place for list partition bounds and add an extra set for range partition bounds. Reported-by: Alexander Lakhin Author: Michael Paquier Reviewed-by: Amit Langote Discussion: https://postgr.es/m/15668-0377b1981aa1a393@postgresql.org
1 parent 2e3da03 commit cdde886

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

src/backend/parser/parse_utilcmd.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3746,12 +3746,24 @@ transformPartitionRangeBounds(ParseState *pstate, List *blist,
37463746
ColumnRef *cref = (ColumnRef *) expr;
37473747
char *cname = NULL;
37483748

3749+
/*
3750+
* There should be a single field named either "minvalue" or
3751+
* "maxvalue".
3752+
*/
37493753
if (list_length(cref->fields) == 1 &&
37503754
IsA(linitial(cref->fields), String))
37513755
cname = strVal(linitial(cref->fields));
37523756

3753-
Assert(cname != NULL);
3754-
if (strcmp("minvalue", cname) == 0)
3757+
if (cname == NULL)
3758+
{
3759+
/*
3760+
* ColumnRef is not in the desired single-field-name form.
3761+
* For consistency between all partition strategies, let the
3762+
* expression transformation report any errors rather than
3763+
* doing it ourselves.
3764+
*/
3765+
}
3766+
else if (strcmp("minvalue", cname) == 0)
37553767
{
37563768
prd = makeNode(PartitionRangeDatum);
37573769
prd->kind = PARTITION_RANGE_DATUM_MINVALUE;

src/test/regress/expected/create_table.out

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,15 @@ Partitions: part_null FOR VALUES IN (NULL),
489489
part_p2 FOR VALUES IN (2),
490490
part_p3 FOR VALUES IN (3)
491491

492-
-- forbidden expressions for partition bound
492+
-- forbidden expressions for partition bound with list partitioned table
493493
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (somename);
494494
ERROR: column "somename" does not exist
495495
LINE 1: ...expr_fail PARTITION OF list_parted FOR VALUES IN (somename);
496496
^
497+
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (somename.somename);
498+
ERROR: missing FROM-clause entry for table "somename"
499+
LINE 1: ...expr_fail PARTITION OF list_parted FOR VALUES IN (somename.s...
500+
^
497501
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (a);
498502
ERROR: cannot use column references in partition bound expression
499503
LINE 1: ..._bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (a);
@@ -502,6 +506,14 @@ CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(a)
502506
ERROR: aggregate functions are not allowed in partition bound
503507
LINE 1: ...s_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(a));
504508
^
509+
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(somename));
510+
ERROR: column "somename" does not exist
511+
LINE 1: ..._fail PARTITION OF list_parted FOR VALUES IN (sum(somename))...
512+
^
513+
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(1));
514+
ERROR: aggregate functions are not allowed in partition bound
515+
LINE 1: ...s_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(1));
516+
^
505517
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN ((select 1));
506518
ERROR: cannot use subquery in partition bound
507519
LINE 1: ...expr_fail PARTITION OF list_parted FOR VALUES IN ((select 1)...
@@ -558,6 +570,47 @@ DROP TABLE bigintp;
558570
CREATE TABLE range_parted (
559571
a date
560572
) PARTITION BY RANGE (a);
573+
-- forbidden expressions for partition bounds with range partitioned table
574+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
575+
FOR VALUES FROM (somename) TO ('2019-01-01');
576+
ERROR: column "somename" does not exist
577+
LINE 2: FOR VALUES FROM (somename) TO ('2019-01-01');
578+
^
579+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
580+
FOR VALUES FROM (somename.somename) TO ('2019-01-01');
581+
ERROR: missing FROM-clause entry for table "somename"
582+
LINE 2: FOR VALUES FROM (somename.somename) TO ('2019-01-01');
583+
^
584+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
585+
FOR VALUES FROM (a) TO ('2019-01-01');
586+
ERROR: cannot use column references in partition bound expression
587+
LINE 2: FOR VALUES FROM (a) TO ('2019-01-01');
588+
^
589+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
590+
FOR VALUES FROM (max(a)) TO ('2019-01-01');
591+
ERROR: aggregate functions are not allowed in partition bound
592+
LINE 2: FOR VALUES FROM (max(a)) TO ('2019-01-01');
593+
^
594+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
595+
FOR VALUES FROM (max(somename)) TO ('2019-01-01');
596+
ERROR: column "somename" does not exist
597+
LINE 2: FOR VALUES FROM (max(somename)) TO ('2019-01-01');
598+
^
599+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
600+
FOR VALUES FROM (max('2019-02-01'::date)) TO ('2019-01-01');
601+
ERROR: aggregate functions are not allowed in partition bound
602+
LINE 2: FOR VALUES FROM (max('2019-02-01'::date)) TO ('2019-01-01'...
603+
^
604+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
605+
FOR VALUES FROM ((select 1)) TO ('2019-01-01');
606+
ERROR: cannot use subquery in partition bound
607+
LINE 2: FOR VALUES FROM ((select 1)) TO ('2019-01-01');
608+
^
609+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
610+
FOR VALUES FROM (generate_series(1, 3)) TO ('2019-01-01');
611+
ERROR: set-returning functions are not allowed in partition bound
612+
LINE 2: FOR VALUES FROM (generate_series(1, 3)) TO ('2019-01-01');
613+
^
561614
-- trying to specify list for range partitioned table
562615
CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES IN ('a');
563616
ERROR: invalid bound specification for a range partition

src/test/regress/sql/create_table.sql

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,10 +450,13 @@ CREATE TABLE part_p3 PARTITION OF list_parted FOR VALUES IN ((2+1));
450450
CREATE TABLE part_null PARTITION OF list_parted FOR VALUES IN (null);
451451
\d+ list_parted
452452

453-
-- forbidden expressions for partition bound
453+
-- forbidden expressions for partition bound with list partitioned table
454454
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (somename);
455+
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (somename.somename);
455456
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (a);
456457
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(a));
458+
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(somename));
459+
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (sum(1));
457460
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN ((select 1));
458461
CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (generate_series(4, 6));
459462

@@ -497,6 +500,24 @@ CREATE TABLE range_parted (
497500
a date
498501
) PARTITION BY RANGE (a);
499502

503+
-- forbidden expressions for partition bounds with range partitioned table
504+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
505+
FOR VALUES FROM (somename) TO ('2019-01-01');
506+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
507+
FOR VALUES FROM (somename.somename) TO ('2019-01-01');
508+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
509+
FOR VALUES FROM (a) TO ('2019-01-01');
510+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
511+
FOR VALUES FROM (max(a)) TO ('2019-01-01');
512+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
513+
FOR VALUES FROM (max(somename)) TO ('2019-01-01');
514+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
515+
FOR VALUES FROM (max('2019-02-01'::date)) TO ('2019-01-01');
516+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
517+
FOR VALUES FROM ((select 1)) TO ('2019-01-01');
518+
CREATE TABLE part_bogus_expr_fail PARTITION OF range_parted
519+
FOR VALUES FROM (generate_series(1, 3)) TO ('2019-01-01');
520+
500521
-- trying to specify list for range partitioned table
501522
CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES IN ('a');
502523
-- trying to specify modulus and remainder for range partitioned table

0 commit comments

Comments
 (0)