aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2019-12-23 12:53:12 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2019-12-23 12:53:12 -0500
commit39ebb943de9dd64e305d17329b8989e3061d03a5 (patch)
treecb756e0af63d8952c1e47e4e476703673bee36b3 /src/backend
parentfc7695891d357a54f0258142de85f88520796b9b (diff)
downloadpostgresql-39ebb943de9dd64e305d17329b8989e3061d03a5.tar.gz
postgresql-39ebb943de9dd64e305d17329b8989e3061d03a5.zip
Disallow partition key expressions that return pseudo-types.
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
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/heap.c43
-rw-r--r--src/backend/commands/tablecmds.c16
2 files changed, 47 insertions, 12 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index ce5a5d741de..452a7f3f953 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -572,6 +572,10 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
* are reliably identifiable only within a session, since the identity info
* may use a typmod that is only locally assigned. The caller is expected
* to know whether these cases are safe.)
+ *
+ * flags can also control the phrasing of the error messages. If
+ * CHKATYPE_IS_PARTKEY is specified, "attname" should be a partition key
+ * column number as text, not a real column name.
* --------------------------------
*/
void
@@ -598,10 +602,19 @@ CheckAttributeType(const char *attname,
if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) ||
(atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) ||
(atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD))))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
- errmsg("column \"%s\" has pseudo-type %s",
- attname, format_type_be(atttypid))));
+ {
+ if (flags & CHKATYPE_IS_PARTKEY)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ /* translator: first %s is an integer not a name */
+ errmsg("partition key column %s has pseudo-type %s",
+ attname, format_type_be(atttypid))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("column \"%s\" has pseudo-type %s",
+ attname, format_type_be(atttypid))));
+ }
}
else if (att_typtype == TYPTYPE_DOMAIN)
{
@@ -648,7 +661,7 @@ CheckAttributeType(const char *attname,
CheckAttributeType(NameStr(attr->attname),
attr->atttypid, attr->attcollation,
containing_rowtypes,
- flags);
+ flags & ~CHKATYPE_IS_PARTKEY);
}
relation_close(relation, AccessShareLock);
@@ -679,11 +692,21 @@ CheckAttributeType(const char *attname,
* useless, and it cannot be dumped, so we must disallow it.
*/
if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
- errmsg("no collation was derived for column \"%s\" with collatable type %s",
- attname, format_type_be(atttypid)),
- errhint("Use the COLLATE clause to set the collation explicitly.")));
+ {
+ if (flags & CHKATYPE_IS_PARTKEY)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ /* translator: first %s is an integer not a name */
+ errmsg("no collation was derived for partition key column %s with collatable type %s",
+ attname, format_type_be(atttypid)),
+ errhint("Use the COLLATE clause to set the collation explicitly.")));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("no collation was derived for column \"%s\" with collatable type %s",
+ attname, format_type_be(atttypid)),
+ errhint("Use the COLLATE clause to set the collation explicitly.")));
+ }
}
/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e8e004eef4d..53a8f1610a4 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4899,8 +4899,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
/*
* Set all columns in the new slot to NULL initially, to ensure
- * columns added as part of the rewrite are initialized to
- * NULL. That is necessary as tab->newvals will not contain an
+ * columns added as part of the rewrite are initialized to NULL.
+ * That is necessary as tab->newvals will not contain an
* expression for columns with a NULL default, e.g. when adding a
* column without a default together with a column with a default
* requiring an actual rewrite.
@@ -15096,12 +15096,24 @@ ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNu
{
/* Expression */
Node *expr = pelem->expr;
+ char partattname[16];
Assert(expr != NULL);
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).
+ */
+ snprintf(partattname, sizeof(partattname), "%d", attn + 1);
+ CheckAttributeType(partattname,
+ atttype, attcollation,
+ NIL, CHKATYPE_IS_PARTKEY);
+
+ /*
* Strip any top-level COLLATE clause. This ensures that we treat
* "x COLLATE y" and "(x COLLATE y)" alike.
*/