diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index a37d1f18be..67b05b8039 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -3746,18 +3746,28 @@ transformPartitionRangeBounds(ParseState *pstate, List *blist, ColumnRef *cref = (ColumnRef *) expr; char *cname = NULL; + /* + * There should be a single field named "minvalue" or "maxvalue". + */ if (list_length(cref->fields) == 1 && IsA(linitial(cref->fields), String)) cname = strVal(linitial(cref->fields)); - Assert(cname != NULL); - if (strcmp("minvalue", cname) == 0) + if (cname == NULL) + { + /* + * ColumnRef is not in the desired single-field-name form; for + * consistency, let transformExpr() report the error rather + * than doing it ourselves. + */ + } + else if (pg_strncasecmp(cname, "minvalue", 6) == 0) { prd = makeNode(PartitionRangeDatum); prd->kind = PARTITION_RANGE_DATUM_MINVALUE; prd->value = NULL; } - else if (strcmp("maxvalue", cname) == 0) + else if (pg_strncasecmp(cname, "maxvalue", 6) == 0) { prd = makeNode(PartitionRangeDatum); prd->kind = PARTITION_RANGE_DATUM_MAXVALUE; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index d51e547278..503dca5866 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -709,6 +709,66 @@ ERROR: modulus for hash partition must be a positive integer -- remainder must be greater than or equal to zero and less than modulus CREATE TABLE fail_part PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 8, REMAINDER 8); ERROR: remainder for hash partition must be less than modulus +-- more tests for generalized expression syntax for list/range partition bounds +CREATE TABLE list_parted_bound_exprs(a int) PARTITION BY LIST (a); +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN ("UNKNOWN"); +ERROR: column "UNKNOWN" does not exist +LINE 1: ...RTITION OF list_parted_bound_exprs FOR VALUES IN ("UNKNOWN")... + ^ +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (a); +ERROR: cannot use column references in partition bound expression +LINE 1: ...prs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (a); + ^ +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (foo.a); +ERROR: missing FROM-clause entry for table "foo" +LINE 1: ... PARTITION OF list_parted_bound_exprs FOR VALUES IN (foo.a); + ^ +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (list_parted_bound_exprs.a); +ERROR: missing FROM-clause entry for table "list_parted_bound_exprs" +LINE 1: ...RTITION OF list_parted_bound_exprs FOR VALUES IN (list_parte... + ^ +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (list_parted_bound_exprs1.a.a.a.a); +ERROR: improper qualified name (too many dotted names): list_parted_bound_exprs1.a.a.a.a +LINE 1: ...RTITION OF list_parted_bound_exprs FOR VALUES IN (list_parte... + ^ +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (list_parted_bound_exprs1.a); +ERROR: cannot use column references in partition bound expression +LINE 1: ...RTITION OF list_parted_bound_exprs FOR VALUES IN (list_parte... + ^ +CREATE TABLE range_parted_bound_exprs(a int) PARTITION BY RANGE (a); +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO (unknown); +ERROR: column "unknown" does not exist +LINE 1: ...F range_parted_bound_exprs FOR VALUES FROM (1) TO (unknown); + ^ +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("a".unknown); +ERROR: missing FROM-clause entry for table "a" +LINE 1: ... range_parted_bound_exprs FOR VALUES FROM (1) TO ("a".unknow... + ^ +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("a"."a"); +ERROR: missing FROM-clause entry for table "a" +LINE 1: ...F range_parted_bound_exprs FOR VALUES FROM (1) TO ("a"."a"); + ^ +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("range_parted_bound_exprs1"."a"); +ERROR: cannot use column references in partition bound expression +LINE 1: ... range_parted_bound_exprs FOR VALUES FROM (1) TO ("range_par... + ^ +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("range_parted_bound_exprs1"."a".a.a); +ERROR: cross-database references are not implemented: range_parted_bound_exprs1.a.a.a +LINE 1: ... range_parted_bound_exprs FOR VALUES FROM (1) TO ("range_par... + ^ +-- the following two should work +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM ("minValue") TO (1); +CREATE TABLE range_parted_bound_exprs2 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO (MAXVALUE); +\d+ range_parted_bound_exprs + Partitioned table "public.range_parted_bound_exprs" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + a | integer | | | | plain | | +Partition key: RANGE (a) +Partitions: range_parted_bound_exprs1 FOR VALUES FROM (MINVALUE) TO (1), + range_parted_bound_exprs2 FOR VALUES FROM (1) TO (MAXVALUE) + +drop table list_parted_bound_exprs, range_parted_bound_exprs; -- check schema propagation from parent CREATE TABLE parted ( a text, diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index 4091c19cf0..399a882430 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -627,6 +627,28 @@ CREATE TABLE fail_part PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 0, REM -- remainder must be greater than or equal to zero and less than modulus CREATE TABLE fail_part PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 8, REMAINDER 8); +-- more tests for generalized expression syntax for list/range partition bounds +CREATE TABLE list_parted_bound_exprs(a int) PARTITION BY LIST (a); +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN ("UNKNOWN"); +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (a); +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (foo.a); +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (list_parted_bound_exprs.a); +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (list_parted_bound_exprs1.a.a.a.a); +CREATE TABLE list_parted_bound_exprs1 PARTITION OF list_parted_bound_exprs FOR VALUES IN (list_parted_bound_exprs1.a); + +CREATE TABLE range_parted_bound_exprs(a int) PARTITION BY RANGE (a); +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO (unknown); +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("a".unknown); +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("a"."a"); +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("range_parted_bound_exprs1"."a"); +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO ("range_parted_bound_exprs1"."a".a.a); +-- the following two should work +CREATE TABLE range_parted_bound_exprs1 PARTITION OF range_parted_bound_exprs FOR VALUES FROM ("minValue") TO (1); +CREATE TABLE range_parted_bound_exprs2 PARTITION OF range_parted_bound_exprs FOR VALUES FROM (1) TO (MAXVALUE); +\d+ range_parted_bound_exprs + +drop table list_parted_bound_exprs, range_parted_bound_exprs; + -- check schema propagation from parent CREATE TABLE parted (