summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Eisentraut2011-03-04 21:39:44 +0000
committerPeter Eisentraut2011-03-04 21:42:07 +0000
commitb9cff97fdf486eca7e563a9696a7391048814d0f (patch)
tree842d92d0efcf3e0fa8118b9a47160e0ad9075da1 /src
parent8d3b421f5f7b955e7ac7d156aa74ee6a6fe4e9f6 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/heap.c17
-rw-r--r--src/backend/catalog/index.c8
-rw-r--r--src/backend/commands/tablecmds.c4
-rw-r--r--src/include/catalog/heap.h2
-rw-r--r--src/test/regress/expected/collate.linux.utf8.out3
-rw-r--r--src/test/regress/sql/collate.linux.utf8.sql2
6 files changed, 28 insertions, 8 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index bfffd6ef4c7..50efa4782d6 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -429,6 +429,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
{
CheckAttributeType(NameStr(tupdesc->attrs[i]->attname),
tupdesc->attrs[i]->atttypid,
+ tupdesc->attrs[i]->attcollation,
allow_system_table_mods);
}
}
@@ -442,7 +443,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
* --------------------------------
*/
void
-CheckAttributeType(const char *attname, Oid atttypid,
+CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation,
bool allow_system_table_mods)
{
char att_typtype = get_typtype(atttypid);
@@ -493,12 +494,24 @@ CheckAttributeType(const char *attname, Oid atttypid,
if (attr->attisdropped)
continue;
- CheckAttributeType(NameStr(attr->attname), attr->atttypid,
+ CheckAttributeType(NameStr(attr->attname), attr->atttypid, attr->attcollation,
allow_system_table_mods);
}
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.")));
}
/*
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 58265129e60..7a2629ecd19 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -352,6 +352,8 @@ ConstructTupleDescriptor(Relation heapRelation,
to->atthasdef = false;
to->attislocal = true;
to->attinhcount = 0;
+
+ to->attcollation = collationObjectId[i];
}
else
{
@@ -388,6 +390,8 @@ ConstructTupleDescriptor(Relation heapRelation,
to->atttypmod = -1;
to->attislocal = true;
+ to->attcollation = collationObjectId[i];
+
ReleaseSysCache(tuple);
/*
@@ -399,11 +403,9 @@ ConstructTupleDescriptor(Relation heapRelation,
* whether a table column is of a safe type (which is why we
* 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
* set it invalid for now. InitializeAttributeOids() will fix it
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e76ce2ceb13..3be9a6f3481 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4206,7 +4206,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
typeOid = HeapTupleGetOid(typeTuple);
/* 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 */
attribute.attrelid = myrelid;
@@ -6515,7 +6515,7 @@ ATPrepAlterColumnType(List **wqueue,
typenameTypeIdModColl(NULL, typeName, &targettype, &targettypmod, &targetcollid);
/* make sure datatype is legal for a column */
- CheckAttributeType(colName, targettype, false);
+ CheckAttributeType(colName, targettype, targetcollid, false);
if (tab->relkind == RELKIND_RELATION)
{
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index f62536a8b21..5f9a864be5f 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -117,7 +117,7 @@ extern Form_pg_attribute SystemAttributeByName(const char *attname,
extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
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);
#endif /* HEAP_H */
diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out
index c793918be4f..caa65b2f37f 100644
--- a/src/test/regress/expected/collate.linux.utf8.out
+++ b/src/test/regress/expected/collate.linux.utf8.out
@@ -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...
^
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
SELECT CAST('42' AS text COLLATE "C");
ERROR: COLLATE clause not allowed in cast target
diff --git a/src/test/regress/sql/collate.linux.utf8.sql b/src/test/regress/sql/collate.linux.utf8.sql
index 9fd55e817e6..c70e5cefd5f 100644
--- a/src/test/regress/sql/collate.linux.utf8.sql
+++ b/src/test/regress/sql/collate.linux.utf8.sql
@@ -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 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