mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Don't allow CREATE TABLE AS to create a column with invalid collation
It is possible that an expression ends up with a collatable type but without a collation. CREATE TABLE AS could then create a table based on that. But such a column cannot be dumped with valid SQL syntax, so we disallow creating such a column. per test report from Noah Misch
This commit is contained in:
@ -429,6 +429,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
|
|||||||
{
|
{
|
||||||
CheckAttributeType(NameStr(tupdesc->attrs[i]->attname),
|
CheckAttributeType(NameStr(tupdesc->attrs[i]->attname),
|
||||||
tupdesc->attrs[i]->atttypid,
|
tupdesc->attrs[i]->atttypid,
|
||||||
|
tupdesc->attrs[i]->attcollation,
|
||||||
allow_system_table_mods);
|
allow_system_table_mods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,7 +443,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
|
|||||||
* --------------------------------
|
* --------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
CheckAttributeType(const char *attname, Oid atttypid,
|
CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation,
|
||||||
bool allow_system_table_mods)
|
bool allow_system_table_mods)
|
||||||
{
|
{
|
||||||
char att_typtype = get_typtype(atttypid);
|
char att_typtype = get_typtype(atttypid);
|
||||||
@ -493,12 +494,24 @@ CheckAttributeType(const char *attname, Oid atttypid,
|
|||||||
|
|
||||||
if (attr->attisdropped)
|
if (attr->attisdropped)
|
||||||
continue;
|
continue;
|
||||||
CheckAttributeType(NameStr(attr->attname), attr->atttypid,
|
CheckAttributeType(NameStr(attr->attname), attr->atttypid, attr->attcollation,
|
||||||
allow_system_table_mods);
|
allow_system_table_mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
relation_close(relation, AccessShareLock);
|
relation_close(relation, AccessShareLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This might not be strictly invalid per SQL standard, but it is
|
||||||
|
* pretty useless, and it cannot be dumped, so we must disallow
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
if (type_is_collatable(atttypid) && !OidIsValid(attcollation))
|
||||||
|
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.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -352,6 +352,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
to->atthasdef = false;
|
to->atthasdef = false;
|
||||||
to->attislocal = true;
|
to->attislocal = true;
|
||||||
to->attinhcount = 0;
|
to->attinhcount = 0;
|
||||||
|
|
||||||
|
to->attcollation = collationObjectId[i];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -388,6 +390,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
to->atttypmod = -1;
|
to->atttypmod = -1;
|
||||||
to->attislocal = true;
|
to->attislocal = true;
|
||||||
|
|
||||||
|
to->attcollation = collationObjectId[i];
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -399,11 +403,9 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
* whether a table column is of a safe type (which is why we
|
* whether a table column is of a safe type (which is why we
|
||||||
* needn't check for the non-expression case).
|
* needn't check for the non-expression case).
|
||||||
*/
|
*/
|
||||||
CheckAttributeType(NameStr(to->attname), to->atttypid, false);
|
CheckAttributeType(NameStr(to->attname), to->atttypid, to->attcollation, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
to->attcollation = collationObjectId[i];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not yet have the correct relation OID for the index, so just
|
* We do not yet have the correct relation OID for the index, so just
|
||||||
* set it invalid for now. InitializeAttributeOids() will fix it
|
* set it invalid for now. InitializeAttributeOids() will fix it
|
||||||
|
@ -4206,7 +4206,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
|||||||
typeOid = HeapTupleGetOid(typeTuple);
|
typeOid = HeapTupleGetOid(typeTuple);
|
||||||
|
|
||||||
/* make sure datatype is legal for a column */
|
/* make sure datatype is legal for a column */
|
||||||
CheckAttributeType(colDef->colname, typeOid, false);
|
CheckAttributeType(colDef->colname, typeOid, collOid, false);
|
||||||
|
|
||||||
/* construct new attribute's pg_attribute entry */
|
/* construct new attribute's pg_attribute entry */
|
||||||
attribute.attrelid = myrelid;
|
attribute.attrelid = myrelid;
|
||||||
@ -6515,7 +6515,7 @@ ATPrepAlterColumnType(List **wqueue,
|
|||||||
typenameTypeIdModColl(NULL, typeName, &targettype, &targettypmod, &targetcollid);
|
typenameTypeIdModColl(NULL, typeName, &targettype, &targettypmod, &targetcollid);
|
||||||
|
|
||||||
/* make sure datatype is legal for a column */
|
/* make sure datatype is legal for a column */
|
||||||
CheckAttributeType(colName, targettype, false);
|
CheckAttributeType(colName, targettype, targetcollid, false);
|
||||||
|
|
||||||
if (tab->relkind == RELKIND_RELATION)
|
if (tab->relkind == RELKIND_RELATION)
|
||||||
{
|
{
|
||||||
|
@ -117,7 +117,7 @@ extern Form_pg_attribute SystemAttributeByName(const char *attname,
|
|||||||
extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
|
extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
|
||||||
bool allow_system_table_mods);
|
bool allow_system_table_mods);
|
||||||
|
|
||||||
extern void CheckAttributeType(const char *attname, Oid atttypid,
|
extern void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation,
|
||||||
bool allow_system_table_mods);
|
bool allow_system_table_mods);
|
||||||
|
|
||||||
#endif /* HEAP_H */
|
#endif /* HEAP_H */
|
||||||
|
@ -627,6 +627,9 @@ ERROR: collation mismatch between implicit collations "en_US.utf8" and "C"
|
|||||||
LINE 1: SELECT a, b FROM collate_test1 EXCEPT SELECT a, b FROM colla...
|
LINE 1: SELECT a, b FROM collate_test1 EXCEPT SELECT a, b FROM colla...
|
||||||
^
|
^
|
||||||
HINT: You can override the collation by applying the COLLATE clause to one or both expressions.
|
HINT: You can override the collation by applying the COLLATE clause to one or both expressions.
|
||||||
|
CREATE TABLE test_u AS SELECT a, b FROM collate_test1 UNION ALL SELECT a, b FROM collate_test3; -- fail
|
||||||
|
ERROR: no collation was derived for column "b" with collatable type text
|
||||||
|
HINT: Use the COLLATE clause to set the collation explicitly.
|
||||||
-- casting
|
-- casting
|
||||||
SELECT CAST('42' AS text COLLATE "C");
|
SELECT CAST('42' AS text COLLATE "C");
|
||||||
ERROR: COLLATE clause not allowed in cast target
|
ERROR: COLLATE clause not allowed in cast target
|
||||||
|
@ -188,6 +188,8 @@ SELECT a, b COLLATE "C" FROM collate_test1 UNION SELECT a, b FROM collate_test3
|
|||||||
SELECT a, b FROM collate_test1 INTERSECT SELECT a, b FROM collate_test3 ORDER BY 2; -- fail
|
SELECT a, b FROM collate_test1 INTERSECT SELECT a, b FROM collate_test3 ORDER BY 2; -- fail
|
||||||
SELECT a, b FROM collate_test1 EXCEPT SELECT a, b FROM collate_test3 ORDER BY 2; -- fail
|
SELECT a, b FROM collate_test1 EXCEPT SELECT a, b FROM collate_test3 ORDER BY 2; -- fail
|
||||||
|
|
||||||
|
CREATE TABLE test_u AS SELECT a, b FROM collate_test1 UNION ALL SELECT a, b FROM collate_test3; -- fail
|
||||||
|
|
||||||
|
|
||||||
-- casting
|
-- casting
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user