* 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
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)
{
CheckAttributeType(NameStr(attr->attname),
attr->atttypid, attr->attcollation,
containing_rowtypes,
- flags);
+ flags & ~CHKATYPE_IS_PARTKEY);
}
relation_close(relation, AccessShareLock);
* 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.")));
+ }
}
/*
/*
* 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.
{
/* 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.
/* flag bits for CheckAttributeType/CheckAttributeNamesTypes */
#define CHKATYPE_ANYARRAY 0x01 /* allow ANYARRAY */
#define CHKATYPE_ANYRECORD 0x02 /* allow RECORD and RECORD[] */
+#define CHKATYPE_IS_PARTKEY 0x04 /* attname is part key # not column */
typedef struct RawColumnDefault
{
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 (
ERROR: cannot use system column "xmin" in partition key
LINE 3: ) PARTITION BY RANGE (xmin);
^
+-- cannot use pseudotypes
+CREATE TABLE partitioned (
+ a int,
+ b int
+) PARTITION BY RANGE (((a, b)));
+ERROR: partition key column 1 has pseudo-type record
+CREATE TABLE partitioned (
+ a int,
+ b int
+) PARTITION BY RANGE (a, ('unknown'));
+ERROR: partition key column 2 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 (
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 (
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 (