diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index b8c4c507a2c5ec68ded8f102e2267cbeea450bbf..c1948624d7033c7b038bbe304ebd2890a2bda614 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -32,9 +32,9 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
 
 <phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
 
-    ADD [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
+    ADD [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
     DROP [ COLUMN ] [ IF EXISTS ] <replaceable class="PARAMETER">column</replaceable> [ RESTRICT | CASCADE ]
-    ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">type</replaceable> [ USING <replaceable class="PARAMETER">expression</replaceable> ]
+    ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ USING <replaceable class="PARAMETER">expression</replaceable> ]
     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET DEFAULT <replaceable class="PARAMETER">expression</replaceable>
     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> DROP DEFAULT
     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | DROP } NOT NULL
@@ -115,7 +115,11 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
       This form changes the type of a column of a table. Indexes and
       simple table constraints involving the column will be automatically
       converted to use the new column type by reparsing the originally
-      supplied expression.  The optional <literal>USING</literal>
+      supplied expression.
+      The optional <literal>COLLATE</literal> clause specifies a collation
+      for the new column; if omitted, the collation is the default for the
+      new column type.
+      The optional <literal>USING</literal>
       clause specifies how to compute the new column value from the old;
       if omitted, the default conversion is the same as an assignment
       cast from old data type to new.  A  <literal>USING</literal>
diff --git a/doc/src/sgml/ref/alter_type.sgml b/doc/src/sgml/ref/alter_type.sgml
index 09db0cc8b2d7aa380460e4f7e16f54928a2f8970..e889ffbc352e41724d0d238f90c50ac13f06ca8e 100644
--- a/doc/src/sgml/ref/alter_type.sgml
+++ b/doc/src/sgml/ref/alter_type.sgml
@@ -32,9 +32,9 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea
 
 <phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
 
-    ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
+    ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ CASCADE | RESTRICT ]
     DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable> [ CASCADE | RESTRICT ]
-    ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
+    ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
diff --git a/doc/src/sgml/ref/create_domain.sgml b/doc/src/sgml/ref/create_domain.sgml
index 83be889c6d9110cc44fa7918dcf274d6825b0f22..2300edefe3a0d8acc7d98170b2aa4560138b0a54 100644
--- a/doc/src/sgml/ref/create_domain.sgml
+++ b/doc/src/sgml/ref/create_domain.sgml
@@ -89,8 +89,9 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea
       <listitem>
        <para>
         An optional collation for the domain.  If no collation is
-        specified, the database default collation is used (which can
-        be overridden when the domain is used to define a column).
+        specified, the underlying data type's default collation is used.
+        The underlying type must be collatable when <literal>COLLATE</>
+        is specified.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 9d2d99ad2e3774654ff9acd3d496de1e6f9b34ee..0fbe1160972e2cc711e57d20a92b23009ca2d6e7 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -248,9 +248,9 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
     <term><literal>COLLATE <replaceable>collation</replaceable></literal></term>
     <listitem>
      <para>
-      The <literal>COLLATE</> clause assigns a nondefault collation to
-      the column.  By default, the locale settings of the database are
-      used.
+      The <literal>COLLATE</> clause assigns a collation to
+      the column (which must be of a collatable data type).
+      If not specified, the column data type's default collation is used.
      </para>
     </listitem>
    </varlistentry>
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 0cd1f941e3fe9bb146190aaaedc79c922bb3448c..d78b08381e00d4d76ce5481c8d536193bfce5de2 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -559,7 +559,8 @@ BuildDescForRelation(List *schema)
 		attnum++;
 
 		attname = entry->colname;
-		typenameTypeIdModColl(NULL, entry->typeName, &atttypid, &atttypmod, &attcollation);
+		typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
+		attcollation = GetColumnDefCollation(NULL, entry, atttypid);
 		attdim = list_length(entry->typeName->arrayBounds);
 
 		if (entry->typeName->setof)
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 18e88d2653fc465fb8c6a072a88f8a5f2da55feb..a52cb351ac83219e4f39276c691f8ad0ab7f919b 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -98,7 +98,7 @@ DefineCollation(List *names, List *parameters)
 		Oid			collid;
 		HeapTuple	tp;
 
-		collid = LookupCollation(NULL, defGetQualifiedName(fromEl), -1);
+		collid =  get_collation_oid(defGetQualifiedName(fromEl), false);
 		tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
 		if (!HeapTupleIsValid(tp))
 			elog(ERROR, "cache lookup failed for collation %u", collid);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 3f25b3bf02a232e4a57bf5679a1e66970335b5c4..a8ef947240e3d7ff178ee42d15bff7f7b6be9a77 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -87,7 +87,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
 	Oid			rettype;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, returnType, NULL, NULL);
+	typtup = LookupTypeName(NULL, returnType, NULL);
 
 	if (typtup)
 	{
@@ -207,7 +207,7 @@ examine_parameter_list(List *parameters, Oid languageOid,
 		Oid			toid;
 		Type		typtup;
 
-		typtup = LookupTypeName(NULL, t, NULL, NULL);
+		typtup = LookupTypeName(NULL, t, NULL);
 		if (typtup)
 		{
 			if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index e71c311faf732a3387bd308690a4014a373cf1c4..5c6212c64cd792c0b272f35f26d214cd6fb85f9d 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -139,9 +139,12 @@ DefineSequence(CreateSeqStmt *seq)
 		coldef->inhcount = 0;
 		coldef->is_local = true;
 		coldef->is_not_null = true;
+		coldef->is_from_type = false;
 		coldef->storage = 0;
 		coldef->raw_default = NULL;
 		coldef->cooked_default = NULL;
+		coldef->collClause = NULL;
+		coldef->collOid = InvalidOid;
 		coldef->constraints = NIL;
 
 		null[i - 1] = false;
@@ -149,53 +152,53 @@ DefineSequence(CreateSeqStmt *seq)
 		switch (i)
 		{
 			case SEQ_COL_NAME:
-				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
 				coldef->colname = "sequence_name";
 				namestrcpy(&name, seq->sequence->relname);
 				value[i - 1] = NameGetDatum(&name);
 				break;
 			case SEQ_COL_LASTVAL:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "last_value";
 				value[i - 1] = Int64GetDatumFast(new.last_value);
 				break;
 			case SEQ_COL_STARTVAL:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "start_value";
 				value[i - 1] = Int64GetDatumFast(new.start_value);
 				break;
 			case SEQ_COL_INCBY:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "increment_by";
 				value[i - 1] = Int64GetDatumFast(new.increment_by);
 				break;
 			case SEQ_COL_MAXVALUE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "max_value";
 				value[i - 1] = Int64GetDatumFast(new.max_value);
 				break;
 			case SEQ_COL_MINVALUE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "min_value";
 				value[i - 1] = Int64GetDatumFast(new.min_value);
 				break;
 			case SEQ_COL_CACHE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "cache_value";
 				value[i - 1] = Int64GetDatumFast(new.cache_value);
 				break;
 			case SEQ_COL_LOG:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "log_cnt";
 				value[i - 1] = Int64GetDatum((int64) 1);
 				break;
 			case SEQ_COL_CYCLE:
-				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
 				coldef->colname = "is_cycled";
 				value[i - 1] = BoolGetDatum(new.is_cycled);
 				break;
 			case SEQ_COL_CALLED:
-				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1, InvalidOid);
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
 				coldef->colname = "is_called";
 				value[i - 1] = BoolGetDatum(false);
 				break;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3be9a6f34815cd05de00668b61c7ca9eabbf7074..f1264bfb66d61595eea92274bd107674f8898397 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -339,7 +339,7 @@ static void ATPrepAlterColumnType(List **wqueue,
 					  AlterTableCmd *cmd, LOCKMODE lockmode);
 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
 static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
-					  const char *colName, TypeName *typeName, LOCKMODE lockmode);
+								  AlterTableCmd *cmd, LOCKMODE lockmode);
 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
 static void ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode);
 static void change_owner_recurse_to_sequences(Oid relationOid,
@@ -1433,7 +1433,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 						(errmsg("merging multiple inherited definitions of column \"%s\"",
 								attributeName)));
 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-				typenameTypeIdModColl(NULL, def->typeName, &defTypeId, &deftypmod, &defCollId);
+				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
 				if (defTypeId != attribute->atttypid ||
 					deftypmod != attribute->atttypmod)
 					ereport(ERROR,
@@ -1443,6 +1443,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 							 errdetail("%s versus %s",
 									   TypeNameToString(def->typeName),
 									   format_type_be(attribute->atttypid))));
+				defCollId = GetColumnDefCollation(NULL, def, defTypeId);
 				if (defCollId != attribute->attcollation)
 					ereport(ERROR,
 							(errcode(ERRCODE_COLLATION_MISMATCH),
@@ -1478,14 +1479,16 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 				def = makeNode(ColumnDef);
 				def->colname = pstrdup(attributeName);
 				def->typeName = makeTypeNameFromOid(attribute->atttypid,
-													attribute->atttypmod,
-													attribute->attcollation);
+													attribute->atttypmod);
 				def->inhcount = 1;
 				def->is_local = false;
 				def->is_not_null = attribute->attnotnull;
+				def->is_from_type = false;
 				def->storage = attribute->attstorage;
 				def->raw_default = NULL;
 				def->cooked_default = NULL;
+				def->collClause = NULL;
+				def->collOid = attribute->attcollation;
 				def->constraints = NIL;
 				inhSchema = lappend(inhSchema, def);
 				newattno[parent_attno - 1] = ++child_attno;
@@ -1616,8 +1619,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 				   (errmsg("merging column \"%s\" with inherited definition",
 						   attributeName)));
 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-				typenameTypeIdModColl(NULL, def->typeName, &defTypeId, &deftypmod, &defcollid);
-				typenameTypeIdModColl(NULL, newdef->typeName, &newTypeId, &newtypmod, &newcollid);
+				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
+				typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
 				if (defTypeId != newTypeId || deftypmod != newtypmod)
 					ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -1626,6 +1629,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 							 errdetail("%s versus %s",
 									   TypeNameToString(def->typeName),
 									   TypeNameToString(newdef->typeName))));
+				defcollid = GetColumnDefCollation(NULL, def, defTypeId);
+				newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
 				if (defcollid != newcollid)
 					ereport(ERROR,
 							(errcode(ERRCODE_COLLATION_MISMATCH),
@@ -3092,7 +3097,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 								 cmd->missing_ok, lockmode);
 			break;
 		case AT_AlterColumnType:		/* ALTER COLUMN TYPE */
-			ATExecAlterColumnType(tab, rel, cmd->name, (TypeName *) cmd->def, lockmode);
+			ATExecAlterColumnType(tab, rel, cmd, lockmode);
 			break;
 		case AT_ChangeOwner:	/* ALTER OWNER */
 			ATExecChangeOwner(RelationGetRelid(rel),
@@ -4129,13 +4134,14 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
 			Oid			ccollid;
 
 			/* Child column must match by type */
-			typenameTypeIdModColl(NULL, colDef->typeName, &ctypeId, &ctypmod, &ccollid);
+			typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
 			if (ctypeId != childatt->atttypid ||
 				ctypmod != childatt->atttypmod)
 				ereport(ERROR,
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
 						 errmsg("child table \"%s\" has different type for column \"%s\"",
 							RelationGetRelationName(rel), colDef->colname)));
+			ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
 			if (ccollid != childatt->attcollation)
 				ereport(ERROR,
 						(errcode(ERRCODE_COLLATION_MISMATCH),
@@ -4201,9 +4207,10 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
 							MaxHeapAttributeNumber)));
 	}
 
-	typeTuple = typenameType(NULL, colDef->typeName, &typmod, &collOid);
+	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
 	typeOid = HeapTupleGetOid(typeTuple);
+	collOid = GetColumnDefCollation(NULL, colDef, typeOid);
 
 	/* make sure datatype is legal for a column */
 	CheckAttributeType(colDef->colname, typeOid, collOid, false);
@@ -4413,7 +4420,7 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
 		ColumnDef  *cdef = makeNode(ColumnDef);
 
 		cdef->colname = pstrdup("oid");
-		cdef->typeName = makeTypeNameFromOid(OIDOID, -1, InvalidOid);
+		cdef->typeName = makeTypeNameFromOid(OIDOID, -1);
 		cdef->inhcount = 0;
 		cdef->is_local = true;
 		cdef->is_not_null = true;
@@ -6471,14 +6478,15 @@ ATPrepAlterColumnType(List **wqueue,
 					  AlterTableCmd *cmd, LOCKMODE lockmode)
 {
 	char	   *colName = cmd->name;
-	TypeName   *typeName = (TypeName *) cmd->def;
+	ColumnDef  *def = (ColumnDef *) cmd->def;
+	TypeName   *typeName = def->typeName;
+	Node	   *transform = def->raw_default;
 	HeapTuple	tuple;
 	Form_pg_attribute attTup;
 	AttrNumber	attnum;
 	Oid			targettype;
 	int32		targettypmod;
 	Oid			targetcollid;
-	Node	   *transform;
 	NewColumnValue *newval;
 	ParseState *pstate = make_parsestate(NULL);
 
@@ -6512,7 +6520,10 @@ ATPrepAlterColumnType(List **wqueue,
 						colName)));
 
 	/* Look up the target type */
-	typenameTypeIdModColl(NULL, typeName, &targettype, &targettypmod, &targetcollid);
+	typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
+
+	/* And the collation */
+	targetcollid = GetColumnDefCollation(NULL, def, targettype);
 
 	/* make sure datatype is legal for a column */
 	CheckAttributeType(colName, targettype, targetcollid, false);
@@ -6527,7 +6538,7 @@ ATPrepAlterColumnType(List **wqueue,
 		 * because we need the expression to be parsed against the original table
 		 * rowtype.
 		 */
-		if (cmd->transform)
+		if (transform)
 		{
 			RangeTblEntry *rte;
 
@@ -6539,7 +6550,7 @@ ATPrepAlterColumnType(List **wqueue,
 												true);
 			addRTEtoQuery(pstate, rte, false, true, true);
 
-			transform = transformExpr(pstate, cmd->transform);
+			transform = transformExpr(pstate, transform);
 
 			/* It can't return a set */
 			if (expression_returns_set(transform))
@@ -6592,16 +6603,13 @@ ATPrepAlterColumnType(List **wqueue,
 		if (ATColumnChangeRequiresRewrite(transform, attnum))
 			tab->rewrite = true;
 	}
-	else if (tab->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		if (cmd->transform)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("ALTER TYPE USING is not supported on foreign tables")));
-	}
+	else if (transform)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("ALTER TYPE USING is only supported on plain tables")));
 
-	if (tab->relkind == RELKIND_COMPOSITE_TYPE
-		|| tab->relkind == RELKIND_FOREIGN_TABLE)
+	if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
+		tab->relkind == RELKIND_FOREIGN_TABLE)
 	{
 		/*
 		 * For composite types, do this check now.  Tables will check
@@ -6667,8 +6675,11 @@ ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
 
 static void
 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
-					  const char *colName, TypeName *typeName, LOCKMODE lockmode)
+					  AlterTableCmd *cmd, LOCKMODE lockmode)
 {
+	char	   *colName = cmd->name;
+	ColumnDef  *def = (ColumnDef *) cmd->def;
+	TypeName   *typeName = def->typeName;
 	HeapTuple	heapTup;
 	Form_pg_attribute attTup;
 	AttrNumber	attnum;
@@ -6705,9 +6716,11 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 						colName)));
 
 	/* Look up the target type (should not fail, since prep found it) */
-	typeTuple = typenameType(NULL, typeName, &targettypmod, &targetcollid);
+	typeTuple = typenameType(NULL, typeName, &targettypmod);
 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
 	targettype = HeapTupleGetOid(typeTuple);
+	/* And the collation */
+	targetcollid = GetColumnDefCollation(NULL, def, targettype);
 
 	/*
 	 * If there is a default expression for the column, get it and ensure we
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index be1f1d791fdddaf86e091dfcc1b327717a36bd13..3513256b9a54874b9c42f1489aff67c1bbcb01ae 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -292,7 +292,7 @@ DefineType(List *names, List *parameters)
 		Type		likeType;
 		Form_pg_type likeForm;
 
-		likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL, NULL);
+		likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
 		likeForm = (Form_pg_type) GETSTRUCT(likeType);
 		internalLength = likeForm->typlen;
 		byValue = likeForm->typbyval;
@@ -649,7 +649,7 @@ RemoveTypes(DropStmt *drop)
 		typename = makeTypeNameFromNameList(names);
 
 		/* Use LookupTypeName here so that shell types can be removed. */
-		tup = LookupTypeName(NULL, typename, NULL, NULL);
+		tup = LookupTypeName(NULL, typename, NULL);
 		if (tup == NULL)
 		{
 			if (!drop->missing_ok)
@@ -774,6 +774,7 @@ DefineDomain(CreateDomainStmt *stmt)
 	Oid			basetypeoid;
 	Oid			domainoid;
 	Oid			old_type_oid;
+	Oid			domaincoll;
 	Form_pg_type baseType;
 	int32		basetypeMod;
 	Oid			baseColl;
@@ -807,7 +808,7 @@ DefineDomain(CreateDomainStmt *stmt)
 	/*
 	 * Look up the base type.
 	 */
-	typeTup = typenameType(NULL, stmt->typeName, &basetypeMod, &baseColl);
+	typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
 	baseType = (Form_pg_type) GETSTRUCT(typeTup);
 	basetypeoid = HeapTupleGetOid(typeTup);
 
@@ -825,6 +826,22 @@ DefineDomain(CreateDomainStmt *stmt)
 				 errmsg("\"%s\" is not a valid base type for a domain",
 						TypeNameToString(stmt->typeName))));
 
+	/*
+	 * Identify the collation if any
+	 */
+	baseColl = baseType->typcollation;
+	if (stmt->collClause)
+		domaincoll = get_collation_oid(stmt->collClause->collnames, false);
+	else
+		domaincoll = baseColl;
+
+	/* Complain if COLLATE is applied to an uncollatable type */
+	if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("collations are not supported by type %s",
+						format_type_be(basetypeoid))));
+
 	/* passed by value */
 	byValue = baseType->typbyval;
 
@@ -1051,7 +1068,7 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   baseColl);
+				   domaincoll);
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -2629,7 +2646,7 @@ AlterTypeOwner(List *names, Oid newOwnerId)
 	typename = makeTypeNameFromNameList(names);
 
 	/* Use LookupTypeName here so that shell types can be processed */
-	tup = LookupTypeName(NULL, typename, NULL, NULL);
+	tup = LookupTypeName(NULL, typename, NULL);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 5576ea259f4bb1ee01c3a4daa9cd95d97481c3d2..794a56e84dee23c9fa3d6b794681e039cae14de9 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -120,14 +120,23 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
 
 			def->colname = pstrdup(tle->resname);
 			def->typeName = makeTypeNameFromOid(exprType((Node *) tle->expr),
-												exprTypmod((Node *) tle->expr),
-												exprCollation((Node *) tle->expr));
+												exprTypmod((Node *) tle->expr));
 			def->inhcount = 0;
 			def->is_local = true;
 			def->is_not_null = false;
+			def->is_from_type = false;
 			def->storage = 0;
 			def->raw_default = NULL;
 			def->cooked_default = NULL;
+			def->collClause = NULL;
+			/*
+			 * XXX Temporary kluge to make regression tests pass.  We should
+			 * be able to trust the result of exprCollation more than this.
+			 */
+			if (type_is_collatable(exprType((Node *) tle->expr)))
+				def->collOid = exprCollation((Node *) tle->expr);
+			else
+				def->collOid = InvalidOid;
 			def->constraints = NIL;
 
 			attrList = lappend(attrList, def);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 86a16783f7174534b399f40e3e0761caaa4c558d..b948af604d8149b9d95f9c923cbb983b2df3eb40 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2183,8 +2183,6 @@ _copyTypeName(TypeName *from)
 	COPY_NODE_FIELD(typmods);
 	COPY_SCALAR_FIELD(typemod);
 	COPY_NODE_FIELD(arrayBounds);
-	COPY_NODE_FIELD(collnames);
-	COPY_SCALAR_FIELD(collOid);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -2295,9 +2293,12 @@ _copyColumnDef(ColumnDef *from)
 	COPY_SCALAR_FIELD(inhcount);
 	COPY_SCALAR_FIELD(is_local);
 	COPY_SCALAR_FIELD(is_not_null);
+	COPY_SCALAR_FIELD(is_from_type);
 	COPY_SCALAR_FIELD(storage);
 	COPY_NODE_FIELD(raw_default);
 	COPY_NODE_FIELD(cooked_default);
+	COPY_NODE_FIELD(collClause);
+	COPY_SCALAR_FIELD(collOid);
 	COPY_NODE_FIELD(constraints);
 
 	return newnode;
@@ -2515,7 +2516,6 @@ _copyAlterTableCmd(AlterTableCmd *from)
 	COPY_SCALAR_FIELD(subtype);
 	COPY_STRING_FIELD(name);
 	COPY_NODE_FIELD(def);
-	COPY_NODE_FIELD(transform);
 	COPY_SCALAR_FIELD(behavior);
 	COPY_SCALAR_FIELD(missing_ok);
 
@@ -3063,6 +3063,7 @@ _copyCreateDomainStmt(CreateDomainStmt *from)
 
 	COPY_NODE_FIELD(domainname);
 	COPY_NODE_FIELD(typeName);
+	COPY_NODE_FIELD(collClause);
 	COPY_NODE_FIELD(constraints);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index c234416cf53022f93b556255b3f5041fa4621a2b..c8ee4744364e7b925415c66c23d0bc2d78b68ffa 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1007,7 +1007,6 @@ _equalAlterTableCmd(AlterTableCmd *a, AlterTableCmd *b)
 	COMPARE_SCALAR_FIELD(subtype);
 	COMPARE_STRING_FIELD(name);
 	COMPARE_NODE_FIELD(def);
-	COMPARE_NODE_FIELD(transform);
 	COMPARE_SCALAR_FIELD(behavior);
 	COMPARE_SCALAR_FIELD(missing_ok);
 
@@ -1461,6 +1460,7 @@ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
 {
 	COMPARE_NODE_FIELD(domainname);
 	COMPARE_NODE_FIELD(typeName);
+	COMPARE_NODE_FIELD(collClause);
 	COMPARE_NODE_FIELD(constraints);
 
 	return true;
@@ -2130,8 +2130,6 @@ _equalTypeName(TypeName *a, TypeName *b)
 	COMPARE_NODE_FIELD(typmods);
 	COMPARE_SCALAR_FIELD(typemod);
 	COMPARE_NODE_FIELD(arrayBounds);
-	COMPARE_NODE_FIELD(collnames);
-	COMPARE_SCALAR_FIELD(collOid);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
@@ -2226,9 +2224,12 @@ _equalColumnDef(ColumnDef *a, ColumnDef *b)
 	COMPARE_SCALAR_FIELD(inhcount);
 	COMPARE_SCALAR_FIELD(is_local);
 	COMPARE_SCALAR_FIELD(is_not_null);
+	COMPARE_SCALAR_FIELD(is_from_type);
 	COMPARE_SCALAR_FIELD(storage);
 	COMPARE_NODE_FIELD(raw_default);
 	COMPARE_NODE_FIELD(cooked_default);
+	COMPARE_NODE_FIELD(collClause);
+	COMPARE_SCALAR_FIELD(collOid);
 	COMPARE_NODE_FIELD(constraints);
 
 	return true;
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 0225f19382a583e6dd0659a9f23d9605961f496a..d9f164523831512c332223dd378ef2603f7ed017 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -427,16 +427,15 @@ makeTypeNameFromNameList(List *names)
 
 /*
  * makeTypeNameFromOid -
- *	build a TypeName node to represent a type already known by OID/typmod/collation.
+ *	build a TypeName node to represent a type already known by OID/typmod.
  */
 TypeName *
-makeTypeNameFromOid(Oid typeOid, int32 typmod, Oid collOid)
+makeTypeNameFromOid(Oid typeOid, int32 typmod)
 {
 	TypeName   *n = makeNode(TypeName);
 
 	n->typeOid = typeOid;
 	n->typemod = typmod;
-	n->collOid = collOid;
 	n->location = -1;
 	return n;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 4aae2b33a6dedf658f511bdac1988a3f03a8998b..06fd7ff818e4ed45c7cbb42ab2ef1f38848839bb 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2067,9 +2067,12 @@ _outColumnDef(StringInfo str, ColumnDef *node)
 	WRITE_INT_FIELD(inhcount);
 	WRITE_BOOL_FIELD(is_local);
 	WRITE_BOOL_FIELD(is_not_null);
+	WRITE_BOOL_FIELD(is_from_type);
 	WRITE_INT_FIELD(storage);
 	WRITE_NODE_FIELD(raw_default);
 	WRITE_NODE_FIELD(cooked_default);
+	WRITE_NODE_FIELD(collClause);
+	WRITE_OID_FIELD(collOid);
 	WRITE_NODE_FIELD(constraints);
 }
 
@@ -2085,8 +2088,6 @@ _outTypeName(StringInfo str, TypeName *node)
 	WRITE_NODE_FIELD(typmods);
 	WRITE_INT_FIELD(typemod);
 	WRITE_NODE_FIELD(arrayBounds);
-	WRITE_NODE_FIELD(collnames);
-	WRITE_OID_FIELD(collOid);
 	WRITE_LOCATION_FIELD(location);
 }
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 5b96b5b0df5e76b3720d7b11e604af5406ecc2ad..373d2adc71c90a58318e9c46e0c55024ab7caede 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -132,6 +132,9 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
 static List *mergeTableFuncParameters(List *func_args, List *columns);
 static TypeName *TableFuncTypeName(List *columns);
 static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner);
+static void SplitColQualList(List *qualList,
+							 List **constraintList, CollateClause **collClause,
+							 core_yyscan_t yyscanner);
 
 %}
 
@@ -221,7 +224,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
 %type <node>	alter_column_default opclass_item opclass_drop alter_using
 %type <ival>	add_drop opt_asc_desc opt_nulls_order
 
-%type <node>	alter_table_cmd alter_type_cmd
+%type <node>	alter_table_cmd alter_type_cmd opt_collate_clause
 %type <list>	alter_table_cmds alter_type_cmds
 
 %type <dbehavior>	opt_drop_behavior
@@ -400,8 +403,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
 %type <list>	copy_generic_opt_list copy_generic_opt_arg_list
 %type <list>	copy_options
 
-%type <typnam>	Typename SimpleTypename SimpleTypenameWithoutCollation
-				ConstTypename
+%type <typnam>	Typename SimpleTypename ConstTypename
 				GenericType Numeric opt_float
 				Character ConstCharacter
 				CharacterWithLength CharacterWithoutLength
@@ -619,6 +621,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
 %left		'^'
 /* Unary Operators */
 %left		AT ZONE			/* sets precedence for AT TIME ZONE */
+%left		COLLATE
 %right		UMINUS
 %left		'[' ']'
 %left		'(' ')'
@@ -1746,13 +1749,17 @@ alter_table_cmd:
 			 * ALTER TABLE <name> ALTER [COLUMN] <colname> [SET DATA] TYPE <typename>
 			 *		[ USING <expression> ]
 			 */
-			| ALTER opt_column ColId opt_set_data TYPE_P Typename alter_using
+			| ALTER opt_column ColId opt_set_data TYPE_P Typename opt_collate_clause alter_using
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
+					ColumnDef *def = makeNode(ColumnDef);
 					n->subtype = AT_AlterColumnType;
 					n->name = $3;
-					n->def = (Node *) $6;
-					n->transform = $7;
+					n->def = (Node *) def;
+					/* We only use these three fields of the ColumnDef node */
+					def->typeName = $6;
+					def->collClause = (CollateClause *) $7;
+					def->raw_default = $8;
 					$$ = (Node *)n;
 				}
 			/* ALTER TABLE <name> ADD CONSTRAINT ... */
@@ -1981,6 +1988,19 @@ opt_drop_behavior:
 			| /* EMPTY */				{ $$ = DROP_RESTRICT; /* default */ }
 		;
 
+opt_collate_clause:
+			COLLATE any_name
+				{
+					CollateClause *n = makeNode(CollateClause);
+					n->arg = NULL;
+					n->collnames = $2;
+					n->collOid = InvalidOid;
+					n->location = @1;
+					$$ = (Node *) n;
+				}
+			| /* EMPTY */				{ $$ = NULL; }
+		;
+
 alter_using:
 			USING a_expr				{ $$ = $2; }
 			| /* EMPTY */				{ $$ = NULL; }
@@ -2077,13 +2097,18 @@ alter_type_cmd:
 					$$ = (Node *)n;
 				}
 			/* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> [RESTRICT|CASCADE] */
-			| ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_drop_behavior
+			| ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_collate_clause opt_drop_behavior
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
+					ColumnDef *def = makeNode(ColumnDef);
 					n->subtype = AT_AlterColumnType;
 					n->name = $3;
-					n->def = (Node *) $6;
-					n->behavior = $7;
+					n->def = (Node *) def;
+					n->behavior = $8;
+					/* We only use these three fields of the ColumnDef node */
+					def->typeName = $6;
+					def->collClause = (CollateClause *) $7;
+					def->raw_default = NULL;
 					$$ = (Node *)n;
 				}
 		;
@@ -2454,8 +2479,16 @@ columnDef:	ColId Typename ColQualList
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
 					n->typeName = $2;
-					n->constraints = $3;
+					n->inhcount = 0;
 					n->is_local = true;
+					n->is_not_null = false;
+					n->is_from_type = false;
+					n->storage = 0;
+					n->raw_default = NULL;
+					n->cooked_default = NULL;
+					n->collOid = InvalidOid;
+					SplitColQualList($3, &n->constraints, &n->collClause,
+									 yyscanner);
 					$$ = (Node *)n;
 				}
 		;
@@ -2464,8 +2497,17 @@ columnOptions:	ColId WITH OPTIONS ColQualList
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
-					n->constraints = $4;
+					n->typeName = NULL;
+					n->inhcount = 0;
 					n->is_local = true;
+					n->is_not_null = false;
+					n->is_from_type = false;
+					n->storage = 0;
+					n->raw_default = NULL;
+					n->cooked_default = NULL;
+					n->collOid = InvalidOid;
+					SplitColQualList($4, &n->constraints, &n->collClause,
+									 yyscanner);
 					$$ = (Node *)n;
 				}
 		;
@@ -2486,6 +2528,20 @@ ColConstraint:
 				}
 			| ColConstraintElem						{ $$ = $1; }
 			| ConstraintAttr						{ $$ = $1; }
+			| COLLATE any_name
+				{
+					/*
+					 * Note: the CollateClause is momentarily included in
+					 * the list built by ColQualList, but we split it out
+					 * again in SplitColQualList.
+					 */
+					CollateClause *n = makeNode(CollateClause);
+					n->arg = NULL;
+					n->collnames = $2;
+					n->collOid = InvalidOid;
+					n->location = @1;
+					$$ = (Node *) n;
+				}
 		;
 
 /* DEFAULT NULL is already the default for Postgres.
@@ -2973,8 +3029,12 @@ CreateAsElement:
 					n->inhcount = 0;
 					n->is_local = true;
 					n->is_not_null = false;
+					n->is_from_type = false;
+					n->storage = 0;
 					n->raw_default = NULL;
 					n->cooked_default = NULL;
+					n->collClause = NULL;
+					n->collOid = InvalidOid;
 					n->constraints = NIL;
 					$$ = (Node *)n;
 				}
@@ -6577,7 +6637,7 @@ opt_column: COLUMN									{ $$ = COLUMN; }
 			| /*EMPTY*/								{ $$ = 0; }
 		;
 
-opt_set_data: SET DATA_P									{ $$ = 1; }
+opt_set_data: SET DATA_P							{ $$ = 1; }
 			| /*EMPTY*/								{ $$ = 0; }
 		;
 
@@ -7443,7 +7503,8 @@ CreateDomainStmt:
 					CreateDomainStmt *n = makeNode(CreateDomainStmt);
 					n->domainname = $3;
 					n->typeName = $5;
-					n->constraints = $6;
+					SplitColQualList($6, &n->constraints, &n->collClause,
+									 yyscanner);
 					$$ = (Node *)n;
 				}
 		;
@@ -9084,13 +9145,21 @@ TableFuncElementList:
 				}
 		;
 
-TableFuncElement:	ColId Typename
+TableFuncElement:	ColId Typename opt_collate_clause
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
 					n->typeName = $2;
-					n->constraints = NIL;
+					n->inhcount = 0;
 					n->is_local = true;
+					n->is_not_null = false;
+					n->is_from_type = false;
+					n->storage = 0;
+					n->raw_default = NULL;
+					n->cooked_default = NULL;
+					n->collClause = (CollateClause *) $3;
+					n->collOid = InvalidOid;
+					n->constraints = NIL;
 					$$ = (Node *)n;
 				}
 		;
@@ -9151,13 +9220,6 @@ opt_array_bounds:
 		;
 
 SimpleTypename:
-			SimpleTypenameWithoutCollation opt_collate
-			{
-				$$ = $1;
-				$$->collnames = $2;
-			}
-
-SimpleTypenameWithoutCollation:
 			GenericType								{ $$ = $1; }
 			| Numeric								{ $$ = $1; }
 			| Bit									{ $$ = $1; }
@@ -9625,6 +9687,14 @@ interval_second:
 a_expr:		c_expr									{ $$ = $1; }
 			| a_expr TYPECAST Typename
 					{ $$ = makeTypeCast($1, $3, @2); }
+			| a_expr COLLATE any_name
+				{
+					CollateClause *n = makeNode(CollateClause);
+					n->arg = (Expr *) $1;
+					n->collnames = $3;
+					n->location = @2;
+					$$ = (Node *) n;
+				}
 			| a_expr AT TIME ZONE a_expr
 				{
 					FuncCall *n = makeNode(FuncCall);
@@ -10193,14 +10263,6 @@ c_expr:		columnref								{ $$ = $1; }
 					r->location = @1;
 					$$ = (Node *)r;
 				}
-			| c_expr COLLATE any_name
-				{
-					CollateClause *n = makeNode(CollateClause);
-					n->arg = (Expr *) $1;
-					n->collnames = $3;
-					n->location = @2;
-					$$ = (Node *)n;
-				}
 		;
 
 /*
@@ -12678,15 +12740,6 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
 	return (Node *) x;
 }
 
-/* parser_init()
- * Initialize to parse one query string
- */
-void
-parser_init(base_yy_extra_type *yyext)
-{
-	yyext->parsetree = NIL;		/* in case grammar forgets to set it */
-}
-
 /*
  * Merge the input and output parameters of a table function.
  */
@@ -12774,6 +12827,57 @@ makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner)
 	return r;
 }
 
+/* Separate Constraint nodes from COLLATE clauses in a ColQualList */
+static void
+SplitColQualList(List *qualList,
+				 List **constraintList, CollateClause **collClause,
+				 core_yyscan_t yyscanner)
+{
+	ListCell   *cell;
+	ListCell   *prev;
+	ListCell   *next;
+
+	*collClause = NULL;
+	prev = NULL;
+	for (cell = list_head(qualList); cell; cell = next)
+	{
+		Node   *n = (Node *) lfirst(cell);
+
+		next = lnext(cell);
+		if (IsA(n, Constraint))
+		{
+			/* keep it in list */
+			prev = cell;
+			continue;
+		}
+		if (IsA(n, CollateClause))
+		{
+			CollateClause *c = (CollateClause *) n;
+
+			if (*collClause)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("multiple COLLATE clauses not allowed"),
+						 parser_errposition(c->location)));
+			*collClause = c;
+		}
+		else
+			elog(ERROR, "unexpected node type %d", (int) n->type);
+		/* remove non-Constraint nodes from qualList */
+		qualList = list_delete_cell(qualList, cell, prev);
+	}
+	*constraintList = qualList;
+}
+
+/* parser_init()
+ * Initialize to parse one query string
+ */
+void
+parser_init(base_yy_extra_type *yyext)
+{
+	yyext->parsetree = NIL;		/* in case grammar forgets to set it */
+}
+
 /*
  * Must undefine this stuff before including scan.c, since it has different
  * definitions for these macros.
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index ae5653259280b140aef1cc03bdbf107d6d91457c..7a4f8cc2497aaf9f669dc3b1d65016a383f425da 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -147,12 +147,6 @@ transformExpr(ParseState *pstate, Node *expr)
 			{
 				TypeCast   *tc = (TypeCast *) expr;
 
-				if (tc->typeName->collnames)
-					ereport(ERROR,
-							(errcode(ERRCODE_SYNTAX_ERROR),
-							 errmsg("COLLATE clause not allowed in cast target"),
-							 parser_errposition(pstate, tc->typeName->location)));
-
 				/*
 				 * If the subject of the typecast is an ARRAY[] construct and
 				 * the target type is an array type, we invoke
@@ -2116,13 +2110,16 @@ transformCollateClause(ParseState *pstate, CollateClause *c)
 	newc->arg = (Expr *) transformExpr(pstate, (Node *) c->arg);
 
 	argtype = exprType((Node *) newc->arg);
-	/* The unknown type is not collatable, but coerce_type() takes
-	 * care of it separately, so we'll let it go here. */
+	/*
+	 * The unknown type is not collatable, but coerce_type() takes
+	 * care of it separately, so we'll let it go here.
+	 */
 	if (!type_is_collatable(argtype) && argtype != UNKNOWNOID)
 		ereport(ERROR,
-				(errcode(ERRCODE_SYNTAX_ERROR),
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
 				 errmsg("collations are not supported by type %s",
-						format_type_be(argtype))));
+						format_type_be(argtype)),
+				 parser_errposition(pstate, c->location)));
 
 	newc->collOid = LookupCollation(pstate, c->collnames, c->location);
 	newc->collnames = c->collnames;
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 0af9cbd92b3dc1364cdefd656cd4e13937ff4b40..a2d6c598104cac0a8e1579984b5abe95a156f2db 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1313,7 +1313,7 @@ FuncNameAsType(List *funcname)
 	Oid			result;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, NULL);
+	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
 	if (typtup == NULL)
 		return InvalidOid;
 
@@ -1500,7 +1500,7 @@ LookupTypeNameOid(const TypeName *typename)
 	Oid			result;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, typename, NULL, NULL);
+	typtup = LookupTypeName(NULL, typename, NULL);
 	if (typtup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index c7000b991534d26f9c9f124059ae3b8243f53c89..488b1425a35db1d002fa0f87a7a0be4988a0bd17 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1169,7 +1169,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
 						 errmsg("column \"%s\" cannot be declared SETOF",
 								attrname),
 						 parser_errposition(pstate, n->typeName->location)));
-			typenameTypeIdModColl(pstate, n->typeName, &attrtype, &attrtypmod, &attrcollation);
+			typenameTypeIdAndMod(pstate, n->typeName, &attrtype, &attrtypmod);
+			attrcollation = GetColumnDefCollation(pstate, n, attrtype);
 			eref->colnames = lappend(eref->colnames, makeString(attrname));
 			rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
 			rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod);
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 20cb47e712f831db014dc08d17427fe0278cb96b..2ba9bf5181642d3f4896c25e14f58ab72800dc08 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -29,8 +29,6 @@
 
 static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
 				Type typ);
-static Oid typenameCollation(ParseState *pstate, const TypeName *typeName,
-				Type typ);
 
 
 /*
@@ -38,8 +36,7 @@ static Oid typenameCollation(ParseState *pstate, const TypeName *typeName,
  *		Given a TypeName object, lookup the pg_type syscache entry of the type.
  *		Returns NULL if no such type can be found.	If the type is found,
  *		the typmod value represented in the TypeName struct is computed and
- *		stored into *typmod_p, and the collation is looked up and stored into
- *      *colloid_p.
+ *		stored into *typmod_p.
  *
  * NB: on success, the caller must ReleaseSysCache the type tuple when done
  * with it.
@@ -54,18 +51,15 @@ static Oid typenameCollation(ParseState *pstate, const TypeName *typeName,
  * found but is a shell, and there is typmod decoration, an error will be
  * thrown --- this is intentional.
  *
- * colloid_p can also be null.
- *
  * pstate is only used for error location info, and may be NULL.
  */
 Type
 LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p, Oid *collid_p)
+			   int32 *typmod_p)
 {
 	Oid			typoid;
 	HeapTuple	tup;
 	int32		typmod;
-	Oid			collid;
 
 	if (typeName->names == NIL)
 	{
@@ -180,28 +174,22 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
 	if (typmod_p)
 		*typmod_p = typmod;
 
-	collid = typenameCollation(pstate, typeName, (Type) tup);
-
-	if (collid_p)
-		*collid_p = collid;
-
 	return (Type) tup;
 }
 
 /*
- * typenameType - given a TypeName, return a Type structure, typmod, and
- * collation
+ * typenameType - given a TypeName, return a Type structure and typmod
  *
  * This is equivalent to LookupTypeName, except that this will report
  * a suitable error message if the type cannot be found or is not defined.
  * Callers of this can therefore assume the result is a fully valid type.
  */
 Type
-typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, Oid *collid_p)
+typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typeName, typmod_p, collid_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -229,7 +217,7 @@ typenameTypeId(ParseState *pstate, const TypeName *typeName)
 	Oid			typoid;
 	Type		tup;
 
-	tup = typenameType(pstate, typeName, NULL, NULL);
+	tup = typenameType(pstate, typeName, NULL);
 	typoid = HeapTupleGetOid(tup);
 	ReleaseSysCache(tup);
 
@@ -248,25 +236,7 @@ typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
 {
 	Type		tup;
 
-	tup = typenameType(pstate, typeName, typmod_p, NULL);
-	*typeid_p = HeapTupleGetOid(tup);
-	ReleaseSysCache(tup);
-}
-
-/*
- * typenameTypeIdModColl - given a TypeName, return the type's OID,
- * typmod, and collation
- *
- * This is equivalent to typenameType, but we only hand back the type OID,
- * typmod, and collation, not the syscache entry.
- */
-void
-typenameTypeIdModColl(ParseState *pstate, const TypeName *typeName,
-					  Oid *typeid_p, int32 *typmod_p, Oid *collid_p)
-{
-	Type		tup;
-
-	tup = typenameType(pstate, typeName, typmod_p, collid_p);
+	tup = typenameType(pstate, typeName, typmod_p);
 	*typeid_p = HeapTupleGetOid(tup);
 	ReleaseSysCache(tup);
 }
@@ -380,62 +350,6 @@ typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
 	return result;
 }
 
-/*
- * typenameCollation - given a TypeName, return the collation OID
- *
- * This will throw an error if the TypeName includes a collation but
- * the data type does not support collations.
- *
- * The actual type OID represented by the TypeName must already have been
- * looked up, and is passed as "typ".
- *
- * pstate is only used for error location info, and may be NULL.
- */
-static Oid
-typenameCollation(ParseState *pstate, const TypeName *typeName, Type typ)
-{
-	Oid typcollation = ((Form_pg_type) GETSTRUCT(typ))->typcollation;
-
-	/* return prespecified collation OID if no collation name specified */
-	if (typeName->collnames == NIL)
-	{
-		if (typeName->collOid == InvalidOid)
-			return typcollation;
-		else
-			return typeName->collOid;
-	}
-
-	if (!OidIsValid(typcollation))
-		ereport(ERROR,
-				(errcode(ERRCODE_SYNTAX_ERROR),
-				 errmsg("collations are not supported by type %s",
-						format_type_be(HeapTupleGetOid(typ))),
-				 parser_errposition(pstate, typeName->location)));
-
-	return LookupCollation(pstate, typeName->collnames, typeName->location);
-}
-
-/*
- * LookupCollation
- *
- * Look up collation by name, return OID, with support for error
- * location.
- */
-Oid
-LookupCollation(ParseState *pstate, List *collnames, int location)
-{
-	Oid			colloid;
-	ParseCallbackState pcbstate;
-
-	setup_parser_errposition_callback(&pcbstate, pstate, location);
-
-	colloid = get_collation_oid(collnames, false);
-
-	cancel_parser_errposition_callback(&pcbstate);
-
-	return colloid;
-}
-
 /*
  * appendTypeNameToBuffer
  *		Append a string representing the name of a TypeName to a StringInfo.
@@ -516,6 +430,72 @@ TypeNameListToString(List *typenames)
 	return string.data;
 }
 
+/*
+ * LookupCollation
+ *
+ * Look up collation by name, return OID, with support for error location.
+ */
+Oid
+LookupCollation(ParseState *pstate, List *collnames, int location)
+{
+	Oid			colloid;
+	ParseCallbackState pcbstate;
+
+	if (pstate)
+		setup_parser_errposition_callback(&pcbstate, pstate, location);
+
+	colloid = get_collation_oid(collnames, false);
+
+	if (pstate)
+		cancel_parser_errposition_callback(&pcbstate);
+
+	return colloid;
+}
+
+/*
+ * GetColumnDefCollation
+ *
+ * Get the collation to be used for a column being defined, given the
+ * ColumnDef node and the previously-determined column type OID.
+ *
+ * pstate is only used for error location purposes, and can be NULL.
+ */
+Oid
+GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
+{
+	Oid			result;
+	Oid			typcollation = get_typcollation(typeOid);
+	int			location = -1;
+
+	if (coldef->collClause)
+	{
+		/* We have a raw COLLATE clause, so look up the collation */
+		location = coldef->collClause->location;
+		result = LookupCollation(pstate, coldef->collClause->collnames,
+								 location);
+	}
+	else if (OidIsValid(coldef->collOid))
+	{
+		/* Precooked collation spec, use that */
+		result = coldef->collOid;
+	}
+	else
+	{
+		/* Use the type's default collation if any */
+		result = typcollation;
+	}
+
+	/* Complain if COLLATE is applied to an uncollatable type */
+	if (OidIsValid(result) && !OidIsValid(typcollation))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("collations are not supported by type %s",
+						format_type_be(typeOid)),
+				 parser_errposition(pstate, location)));
+
+	return result;
+}
+
 /* return a Type structure, given a type id */
 /* NB: caller must ReleaseSysCache the type tuple when done with it */
 Type
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 61ce840a5e59395cbfe1e72d4b04235cd6f230e5..e876853af02c9a37b74e4031ea46a753898b4876 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -627,13 +627,16 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
 		def = makeNode(ColumnDef);
 		def->colname = pstrdup(attributeName);
 		def->typeName = makeTypeNameFromOid(attribute->atttypid,
-											attribute->atttypmod,
-											attribute->attcollation);
+											attribute->atttypmod);
 		def->inhcount = 0;
 		def->is_local = true;
 		def->is_not_null = attribute->attnotnull;
+		def->is_from_type = false;
+		def->storage = 0;
 		def->raw_default = NULL;
 		def->cooked_default = NULL;
+		def->collClause = NULL;
+		def->collOid = attribute->attcollation;
 		def->constraints = NIL;
 
 		/*
@@ -822,7 +825,7 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
 
 	AssertArg(ofTypename);
 
-	tuple = typenameType(NULL, ofTypename, NULL, NULL);
+	tuple = typenameType(NULL, ofTypename, NULL);
 	typ = (Form_pg_type) GETSTRUCT(tuple);
 	ofTypeId = HeapTupleGetOid(tuple);
 	ofTypename->typeOid = ofTypeId;		/* cached for later */
@@ -837,16 +840,24 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
 	for (i = 0; i < tupdesc->natts; i++)
 	{
 		Form_pg_attribute attr = tupdesc->attrs[i];
-		ColumnDef  *n = makeNode(ColumnDef);
+		ColumnDef  *n;
 
 		if (attr->attisdropped)
 			continue;
 
+		n = makeNode(ColumnDef);
 		n->colname = pstrdup(NameStr(attr->attname));
-		n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod, attr->attcollation);
-		n->constraints = NULL;
+		n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod);
+		n->inhcount = 0;
 		n->is_local = true;
+		n->is_not_null = false;
 		n->is_from_type = true;
+		n->storage = 0;
+		n->raw_default = NULL;
+		n->cooked_default = NULL;
+		n->collClause = NULL;
+		n->collOid = attr->attcollation;
+		n->constraints = NIL;
 		cxt->columns = lappend(cxt->columns, n);
 	}
 	DecrTupleDescRefCount(tupdesc);
@@ -2445,9 +2456,28 @@ static void
 transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
 {
 	/*
-	 * All we really need to do here is verify that the type is valid.
+	 * All we really need to do here is verify that the type is valid,
+	 * including any collation spec that might be present.
 	 */
-	Type		ctype = typenameType(cxt->pstate, column->typeName, NULL, NULL);
+	Type		ctype = typenameType(cxt->pstate, column->typeName, NULL);
+
+	if (column->collClause)
+	{
+		Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype);
+		Oid		collOid;
+
+		collOid = LookupCollation(cxt->pstate,
+								  column->collClause->collnames,
+								  column->collClause->location);
+		/* Complain if COLLATE is applied to an uncollatable type */
+		if (!OidIsValid(typtup->typcollation))
+			ereport(ERROR,
+					(errcode(ERRCODE_DATATYPE_MISMATCH),
+					 errmsg("collations are not supported by type %s",
+							format_type_be(HeapTupleGetOid(ctype))),
+					 parser_errposition(cxt->pstate,
+										column->collClause->location)));
+	}
 
 	ReleaseSysCache(ctype);
 }
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 025edf0838657d848524d65ff0b285fca42b2a6a..7cbd0222cb2e77b59ec3264c8ffabb68addeb1a5 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5082,8 +5082,9 @@ get_rule_expr(Node *node, deparse_context *context,
 
 				if (!PRETTY_PAREN(context))
 					appendStringInfoChar(buf, '(');
-				get_rule_expr_paren(arg, context, false, node);
-				appendStringInfo(buf, " COLLATE %s", generate_collation_name(collate->collOid));
+				get_rule_expr_paren(arg, context, showimplicit, node);
+				appendStringInfo(buf, " COLLATE %s",
+								 generate_collation_name(collate->collOid));
 				if (!PRETTY_PAREN(context))
 					appendStringInfoChar(buf, ')');
 			}
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index 8b7db798b9cd0d087d4960c9557891f5033990c7..6691b0dc77eeb3567f66119af04fc46fd13ffb4f 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -68,7 +68,7 @@ extern RangeVar *makeRangeVar(char *schemaname, char *relname, int location);
 
 extern TypeName *makeTypeName(char *typnam);
 extern TypeName *makeTypeNameFromNameList(List *names);
-extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod, Oid collOid);
+extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod);
 
 extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype,
 			 List *args, Oid collid, CoercionForm fformat);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 287e9f523ff4ba6a520b9df47d23090defe086de..9d4515cb27f39f5cae6165eb7385982a67aeb397 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -168,8 +168,7 @@ typedef struct Query
  * specify the type by OID than by name.  If "names" is NIL then the
  * actual type OID is given by typeOid, otherwise typeOid is unused.
  * Similarly, if "typmods" is NIL then the actual typmod is expected to
- * be prespecified in typemod, otherwise typemod is unused.  Similarly
- * for collnames/collOid.
+ * be prespecified in typemod, otherwise typemod is unused.
  *
  * If pct_type is TRUE, then names is actually a field name and we look up
  * the type of that field.	Otherwise (the normal case), names is a type
@@ -185,8 +184,6 @@ typedef struct TypeName
 	List	   *typmods;		/* type modifier expression(s) */
 	int32		typemod;		/* prespecified type modifier */
 	List	   *arrayBounds;	/* array bounds */
-	List	   *collnames;		/* collation name */
-	Oid			collOid;		/* collation by OID */
 	int			location;		/* token location, or -1 if unknown */
 } TypeName;
 
@@ -468,6 +465,10 @@ typedef struct RangeFunction
  * how this ColumnDef node was created (by parsing, or by inheritance
  * from an existing relation).	We should never have both in the same node!
  *
+ * Similarly, we may have a COLLATE specification in either raw form
+ * (represented as a CollateClause with arg==NULL) or cooked form
+ * (the collation's OID).
+ *
  * The constraints list may contain a CONSTR_DEFAULT item in a raw
  * parsetree produced by gram.y, but transformCreateStmt will remove
  * the item and set raw_default instead.  CONSTR_DEFAULT items
@@ -485,6 +486,8 @@ typedef struct ColumnDef
 	char		storage;		/* attstorage setting, or 0 for default */
 	Node	   *raw_default;	/* default value (untransformed parse tree) */
 	Node	   *cooked_default; /* default value (transformed expr tree) */
+	CollateClause *collClause;	/* untransformed COLLATE spec, if any */
+	Oid			collOid;		/* collation OID (InvalidOid if not set) */
 	List	   *constraints;	/* other constraints on column */
 } ColumnDef;
 
@@ -1202,9 +1205,8 @@ typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
 	AlterTableType subtype;		/* Type of table alteration to apply */
 	char	   *name;			/* column, constraint, or trigger to act on,
 								 * or new owner or tablespace */
-	Node	   *def;			/* definition of new column, column type,
-								 * index, constraint, or parent table */
-	Node	   *transform;		/* transformation expr for ALTER TYPE */
+	Node	   *def;			/* definition of new column, index,
+								 * constraint, or parent table */
 	DropBehavior behavior;		/* RESTRICT or CASCADE for DROP cases */
 	bool		missing_ok;		/* skip error if missing? */
 	bool		validated;
@@ -1819,6 +1821,7 @@ typedef struct CreateDomainStmt
 	NodeTag		type;
 	List	   *domainname;		/* qualified name (list of Value strings) */
 	TypeName   *typeName;		/* the base type */
+	CollateClause *collClause;	/* untransformed COLLATE spec, if any */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
 } CreateDomainStmt;
 
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 8621ab678d0d7ef46102efc28953c592a74914c9..92c9ecba4acc7303a3a3c0ba4bf1f402d26dbb81 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,21 +20,19 @@
 typedef HeapTuple Type;
 
 extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
-						   int32 *typmod_p, Oid *collid_p);
+			   int32 *typmod_p);
 extern Type typenameType(ParseState *pstate, const TypeName *typeName,
-						 int32 *typmod_p, Oid *collid_p);
-
-extern Oid LookupCollation(ParseState *pstate, List *collnames, int location);
-
+			 int32 *typmod_p);
 extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName);
 extern void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
-								  Oid *typeid_p, int32 *typmod_p);
-extern void typenameTypeIdModColl(ParseState *pstate, const TypeName *typeName,
-								  Oid *typeid_p, int32 *typmod_p, Oid *collid_p);
+								 Oid *typeid_p, int32 *typmod_p);
 
 extern char *TypeNameToString(const TypeName *typeName);
 extern char *TypeNameListToString(List *typenames);
 
+extern Oid LookupCollation(ParseState *pstate, List *collnames, int location);
+extern Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid);
+
 extern Type typeidType(Oid id);
 
 extern Oid	typeTypeId(Type tp);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index d2b3862ec722a6c30ad24096af79f04ba7f316a7..41188a2369fd3632adbb7496c02d80e9ef964075 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1565,7 +1565,7 @@ plpgsql_parse_wordtype(char *ident)
 	 * Word wasn't found in the namespace stack. Try to find a data type with
 	 * that name, but ignore shell types and complex types.
 	 */
-	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, NULL);
+	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
 	if (typeTup)
 	{
 		Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out
index caa65b2f37f881cdfa817f6d8c9008cd56c1ab79..5ad5de2f00b36f8f65b68fadb8f19b12b3add2b9 100644
--- a/src/test/regress/expected/collate.linux.utf8.out
+++ b/src/test/regress/expected/collate.linux.utf8.out
@@ -20,21 +20,21 @@ CREATE TABLE collate_test_fail (
 );
 ERROR:  collation "ja_JP.eucjp" for current database encoding "UTF8" does not exist
 LINE 3:     b text COLLATE "ja_JP.eucjp"
-              ^
+                   ^
 CREATE TABLE collate_test_fail (
     a int,
     b text COLLATE "foo"
 );
 ERROR:  collation "foo" for current database encoding "UTF8" does not exist
 LINE 3:     b text COLLATE "foo"
-              ^
+                   ^
 CREATE TABLE collate_test_fail (
     a int COLLATE "en_US.utf8",
     b text
 );
 ERROR:  collations are not supported by type integer
 LINE 2:     a int COLLATE "en_US.utf8",
-              ^
+                  ^
 CREATE TABLE collate_test_like (
     LIKE collate_test1
 );
@@ -632,9 +632,9 @@ 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
+ERROR:  syntax error at or near "COLLATE"
 LINE 1: SELECT CAST('42' AS text COLLATE "C");
-                            ^
+                                 ^
 SELECT a, CAST(b AS varchar) FROM collate_test1 ORDER BY 2;
  a |  b  
 ---+-----
@@ -727,6 +727,8 @@ CREATE INDEX collate_test1_idx4 ON collate_test1 (a COLLATE "C"); -- fail
 ERROR:  collations are not supported by type integer
 CREATE INDEX collate_test1_idx5 ON collate_test1 ((a COLLATE "C")); -- fail
 ERROR:  collations are not supported by type integer
+LINE 1: ...ATE INDEX collate_test1_idx5 ON collate_test1 ((a COLLATE "C...
+                                                             ^
 SELECT relname, pg_get_indexdef(oid) FROM pg_class WHERE relname LIKE 'collate_test%_idx%';
       relname       |                                       pg_get_indexdef                                        
 --------------------+----------------------------------------------------------------------------------------------
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index 00730f25cb83847e71878e9d517766bde1fc537b..a7473349fdf0cad58f0a3ff8b015fee73eaf2550 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -693,7 +693,7 @@ ERROR:  "ft1" is not a table or view
 ALTER FOREIGN TABLE ft1 ALTER COLUMN c6 SET NOT NULL;
 ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL;
 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR
-ERROR:  ALTER TYPE USING is not supported on foreign tables
+ERROR:  ALTER TYPE USING is only supported on plain tables
 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
 -- can't change the column type if it's used elsewhere