partition-bound-crash-v2.patch

text/plain

Filename: partition-bound-crash-v2.patch
Type: text/plain
Part: 0
Message: Re: BUG #15668: Server crash in transformPartitionRangeBounds

Patch

Format: unified
Series: patch v2
File+
src/backend/parser/parse_utilcmd.c 13 3
src/test/regress/expected/create_table.out 60 0
src/test/regress/sql/create_table.sql 22 0
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 (