Disallow partition key expressions that return pseudo-types.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 23 Dec 2019 17:53:13 +0000 (12:53 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 23 Dec 2019 17:53:13 +0000 (12:53 -0500)
This wasn't checked originally, but it should have been, because
in general pseudo-types can't be stored to and retrieved from disk.
Notably, partition bound values of type "record" would not be
interpretable by another session.

In v12 and HEAD, add another flag to CheckAttributeType's repertoire
so that it can produce a specific error message for this case.  That's
infeasible in older branches without an ABI break, so fall back to
a slightly-less-nicely-worded error message in v10 and v11.

Problem noted by Amit Langote, though this patch is not his initial
solution.  Back-patch to v10 where partitioning was introduced.

Discussion: https://postgr.es/m/CA+HiwqFUzjfj9HEsJtYWcr1SgQ_=iCAvQ=O2Sx6aQxoDu4OiHw@mail.gmail.com

src/backend/commands/tablecmds.c
src/test/regress/expected/create_table.out
src/test/regress/sql/create_table.sql

index 9a1ef78a1fb06df975529db2b09cafd65c537fb1..d207bc299f969f0cf804a8d59d258313807bd073 100644 (file)
@@ -14402,6 +14402,16 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
            atttype = exprType(expr);
            attcollation = exprCollation(expr);
 
+           /*
+            * The expression must be of a storable type (e.g., not RECORD).
+            * The test is the same as for whether a table column is of a safe
+            * type (which is why we needn't check for the non-expression
+            * case).
+            */
+           CheckAttributeType("partition key",
+                              atttype, attcollation,
+                              NIL, false);
+
            /*
             * Strip any top-level COLLATE clause.  This ensures that we treat
             * "x COLLATE y" and "(x COLLATE y)" alike.
index d20ba3dbdf57ac68d2010fa272db7bd4c04164e3..f44024aedcc3abac26efdb0b075cfb5fd5104c20 100644 (file)
@@ -334,7 +334,7 @@ CREATE TABLE partitioned (
 ERROR:  cannot use subquery in partition key expression
 CREATE TABLE partitioned (
    a int
-) PARTITION BY RANGE (('a'));
+) PARTITION BY RANGE ((42));
 ERROR:  cannot use constant expression as partition key
 CREATE FUNCTION const_func () RETURNS int AS $$ SELECT 1; $$ LANGUAGE SQL IMMUTABLE;
 CREATE TABLE partitioned (
@@ -357,6 +357,17 @@ CREATE TABLE partitioned (
    a int
 ) PARTITION BY RANGE (xmin);
 ERROR:  cannot use system column "xmin" in partition key
+-- cannot use pseudotypes
+CREATE TABLE partitioned (
+   a int,
+   b int
+) PARTITION BY RANGE (((a, b)));
+ERROR:  column "partition key" has pseudo-type record
+CREATE TABLE partitioned (
+   a int,
+   b int
+) PARTITION BY RANGE (a, ('unknown'));
+ERROR:  column "partition key" has pseudo-type unknown
 -- functions in key must be immutable
 CREATE FUNCTION immut_func (a int) RETURNS int AS $$ SELECT a + random()::int; $$ LANGUAGE SQL;
 CREATE TABLE partitioned (
index 601a4b9dc3e7192609a33051f90cbfc79ea86976..dc5b729ad8e05b0112c76a9fa16e3ee85f035b00 100644 (file)
@@ -343,7 +343,7 @@ CREATE TABLE partitioned (
 
 CREATE TABLE partitioned (
    a int
-) PARTITION BY RANGE (('a'));
+) PARTITION BY RANGE ((42));
 
 CREATE FUNCTION const_func () RETURNS int AS $$ SELECT 1; $$ LANGUAGE SQL IMMUTABLE;
 CREATE TABLE partitioned (
@@ -366,6 +366,16 @@ CREATE TABLE partitioned (
    a int
 ) PARTITION BY RANGE (xmin);
 
+-- cannot use pseudotypes
+CREATE TABLE partitioned (
+   a int,
+   b int
+) PARTITION BY RANGE (((a, b)));
+CREATE TABLE partitioned (
+   a int,
+   b int
+) PARTITION BY RANGE (a, ('unknown'));
+
 -- functions in key must be immutable
 CREATE FUNCTION immut_func (a int) RETURNS int AS $$ SELECT a + random()::int; $$ LANGUAGE SQL;
 CREATE TABLE partitioned (