<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
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>
<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>
<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>
<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>
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)
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);
Oid rettype;
Type typtup;
- typtup = LookupTypeName(NULL, returnType, NULL, NULL);
+ typtup = LookupTypeName(NULL, returnType, NULL);
if (typtup)
{
Oid toid;
Type typtup;
- typtup = LookupTypeName(NULL, t, NULL, NULL);
+ typtup = LookupTypeName(NULL, t, NULL);
if (typtup)
{
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
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;
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;
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,
(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,
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),
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;
(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),
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),
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),
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),
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);
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;
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);
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);
* because we need the expression to be parsed against the original table
* rowtype.
*/
- if (cmd->transform)
+ if (transform)
{
RangeTblEntry *rte;
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))
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
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;
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
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;
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)
Oid basetypeoid;
Oid domainoid;
Oid old_type_oid;
+ Oid domaincoll;
Form_pg_type baseType;
int32 basetypeMod;
Oid baseColl;
/*
* 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);
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;
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
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),
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);
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;
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;
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);
COPY_NODE_FIELD(domainname);
COPY_NODE_FIELD(typeName);
+ COPY_NODE_FIELD(collClause);
COPY_NODE_FIELD(constraints);
return newnode;
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);
{
COMPARE_NODE_FIELD(domainname);
COMPARE_NODE_FIELD(typeName);
+ COMPARE_NODE_FIELD(collClause);
COMPARE_NODE_FIELD(constraints);
return true;
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;
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;
/*
* 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;
}
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);
}
WRITE_NODE_FIELD(typmods);
WRITE_INT_FIELD(typemod);
WRITE_NODE_FIELD(arrayBounds);
- WRITE_NODE_FIELD(collnames);
- WRITE_OID_FIELD(collOid);
WRITE_LOCATION_FIELD(location);
}
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);
%}
%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
%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
%left '^'
/* Unary Operators */
%left AT ZONE /* sets precedence for AT TIME ZONE */
+%left COLLATE
%right UMINUS
%left '[' ']'
%left '(' ')'
* 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 ... */
| /* 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; }
$$ = (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;
}
;
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;
}
;
{
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;
}
;
}
| 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.
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;
}
| /*EMPTY*/ { $$ = 0; }
;
-opt_set_data: SET DATA_P { $$ = 1; }
+opt_set_data: SET DATA_P { $$ = 1; }
| /*EMPTY*/ { $$ = 0; }
;
CreateDomainStmt *n = makeNode(CreateDomainStmt);
n->domainname = $3;
n->typeName = $5;
- n->constraints = $6;
+ SplitColQualList($6, &n->constraints, &n->collClause,
+ yyscanner);
$$ = (Node *)n;
}
;
}
;
-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;
}
;
;
SimpleTypename:
- SimpleTypenameWithoutCollation opt_collate
- {
- $$ = $1;
- $$->collnames = $2;
- }
-
-SimpleTypenameWithoutCollation:
GenericType { $$ = $1; }
| Numeric { $$ = $1; }
| Bit { $$ = $1; }
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);
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;
- }
;
/*
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.
*/
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.
{
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
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;
Oid result;
Type typtup;
- typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, NULL);
+ typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
if (typtup == NULL)
return InvalidOid;
Oid result;
Type typtup;
- typtup = LookupTypeName(NULL, typename, NULL, NULL);
+ typtup = LookupTypeName(NULL, typename, NULL);
if (typtup == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
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);
static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
Type typ);
-static Oid typenameCollation(ParseState *pstate, const TypeName *typeName,
- Type typ);
/*
* 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.
* 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)
{
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),
Oid typoid;
Type tup;
- tup = typenameType(pstate, typeName, NULL, NULL);
+ tup = typenameType(pstate, typeName, NULL);
typoid = HeapTupleGetOid(tup);
ReleaseSysCache(tup);
{
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);
}
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.
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
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;
/*
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 */
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);
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);
}
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, ')');
}
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);
* 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
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;
* 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
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;
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;
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;
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);
* 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);
);
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
);
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
---+-----
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
--------------------+----------------------------------------------------------------------------------------------
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