aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y182
-rw-r--r--src/backend/parser/parse_expr.c17
-rw-r--r--src/backend/parser/parse_func.c4
-rw-r--r--src/backend/parser/parse_relation.c3
-rw-r--r--src/backend/parser/parse_type.c166
-rw-r--r--src/backend/parser/parse_utilcmd.c46
6 files changed, 265 insertions, 153 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 5b96b5b0df5..373d2adc71c 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 ae565325928..7a4f8cc2497 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 0af9cbd92b3..a2d6c598104 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 c7000b99153..488b1425a35 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 20cb47e712f..2ba9bf51816 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);
}
@@ -381,62 +351,6 @@ typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
}
/*
- * 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.
* This is the shared guts of TypeNameToString and TypeNameListToString.
@@ -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 61ce840a5e5..e876853af02 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);
}