aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/tupdesc.c6
-rw-r--r--src/backend/catalog/dependency.c4
-rw-r--r--src/backend/catalog/heap.c10
-rw-r--r--src/backend/catalog/index.c14
-rw-r--r--src/backend/catalog/pg_type.c5
-rw-r--r--src/backend/commands/indexcmds.c6
-rw-r--r--src/backend/commands/tablecmds.c38
-rw-r--r--src/backend/commands/typecmds.c10
-rw-r--r--src/backend/executor/nodeMergejoin.c8
-rw-r--r--src/backend/optimizer/plan/createplan.c57
-rw-r--r--src/backend/optimizer/plan/subselect.c11
-rw-r--r--src/backend/parser/analyze.c10
-rw-r--r--src/backend/parser/parse_cte.c18
-rw-r--r--src/backend/parser/parse_relation.c8
-rw-r--r--src/backend/parser/parse_target.c13
-rw-r--r--src/backend/utils/adt/ruleutils.c9
-rw-r--r--src/backend/utils/cache/syscache.c4
17 files changed, 144 insertions, 87 deletions
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index c06a0271ca5..16979c4ea72 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -360,6 +360,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
return false;
if (attr1->attinhcount != attr2->attinhcount)
return false;
+ if (attr1->attcollation != attr2->attcollation)
+ return false;
/* attacl and attoptions are not even present... */
}
@@ -611,7 +613,9 @@ BuildDescForRelation(List *schema)
* BuildDescFromLists
*
* Build a TupleDesc given lists of column names (as String nodes),
- * column type OIDs, and column typmods. No constraints are generated.
+ * column type OIDs, typmods, and collation OIDs.
+ *
+ * No constraints are generated.
*
* This is essentially a cut-down version of BuildDescForRelation for use
* with functions returning RECORD.
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index b3ed946530e..c459c1e2213 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -2227,14 +2227,16 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_COLLATION:
{
HeapTuple collTup;
+ Form_pg_collation coll;
collTup = SearchSysCache1(COLLOID,
ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(collTup))
elog(ERROR, "cache lookup failed for collation %u",
object->objectId);
+ coll = (Form_pg_collation) GETSTRUCT(collTup);
appendStringInfo(&buffer, _("collation %s"),
- NameStr(((Form_pg_collation) GETSTRUCT(collTup))->collname));
+ NameStr(coll->collname));
ReleaseSysCache(collTup);
break;
}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 8c5670fdb8c..28d5c549a32 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -644,7 +644,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
/*
* First we add the user attributes. This is also a convenient place to
- * add dependencies on their datatypes.
+ * add dependencies on their datatypes and collations.
*/
for (i = 0; i < natts; i++)
{
@@ -666,7 +666,9 @@ AddNewAttributeTuples(Oid new_rel_oid,
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
- if (OidIsValid(attr->attcollation))
+ /* The default collation is pinned, so don't bother recording it */
+ if (OidIsValid(attr->attcollation) &&
+ attr->attcollation != DEFAULT_COLLATION_OID)
{
referenced.classId = CollationRelationId;
referenced.objectId = attr->attcollation;
@@ -921,7 +923,7 @@ AddNewRelationType(const char *typeName,
-1, /* typmod */
0, /* array dimensions for typBaseType */
false, /* Type NOT NULL */
- InvalidOid); /* typcollation */
+ InvalidOid); /* rowtypes never have a collation */
}
/* --------------------------------
@@ -1183,7 +1185,7 @@ heap_create_with_catalog(const char *relname,
-1, /* typmod */
0, /* array dimensions for typBaseType */
false, /* Type NOT NULL */
- InvalidOid); /* typcollation */
+ InvalidOid); /* rowtypes never have a collation */
pfree(relarrayname);
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index c79402c72a9..bc630a6f3ac 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -351,7 +351,6 @@ ConstructTupleDescriptor(Relation heapRelation,
to->atthasdef = false;
to->attislocal = true;
to->attinhcount = 0;
-
to->attcollation = collationObjectId[i];
}
else
@@ -388,7 +387,6 @@ ConstructTupleDescriptor(Relation heapRelation,
to->attcacheoff = -1;
to->atttypmod = -1;
to->attislocal = true;
-
to->attcollation = collationObjectId[i];
ReleaseSysCache(tuple);
@@ -653,6 +651,7 @@ UpdateIndexRelation(Oid indexoid,
* indexColNames: column names to use for index (List of char *)
* accessMethodObjectId: OID of index AM to use
* tableSpaceId: OID of tablespace to use
+ * collationObjectId: array of collation OIDs, one per index column
* classObjectId: array of index opclass OIDs, one per index column
* coloptions: array of per-index-column indoption settings
* reloptions: AM-specific options
@@ -871,7 +870,8 @@ index_create(Relation heapRelation,
* ----------------
*/
UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo,
- collationObjectId, classObjectId, coloptions, isprimary, is_exclusion,
+ collationObjectId, classObjectId, coloptions,
+ isprimary, is_exclusion,
!deferrable,
!concurrent);
@@ -965,9 +965,11 @@ index_create(Relation heapRelation,
}
/* Store dependency on collations */
+ /* The default collation is pinned, so don't bother recording it */
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
{
- if (OidIsValid(collationObjectId[i]))
+ if (OidIsValid(collationObjectId[i]) &&
+ collationObjectId[i] != DEFAULT_COLLATION_OID)
{
referenced.classId = CollationRelationId;
referenced.objectId = collationObjectId[i];
@@ -2445,8 +2447,8 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
ivinfo.strategy = NULL;
- state.tuplesort = tuplesort_begin_datum(TIDOID,
- TIDLessOperator, InvalidOid, false,
+ state.tuplesort = tuplesort_begin_datum(TIDOID, TIDLessOperator,
+ InvalidOid, false,
maintenance_work_mem,
false);
state.htups = state.itups = state.tups_inserted = 0;
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 9e35e73f9cf..b6912578786 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -643,8 +643,9 @@ GenerateTypeDependencies(Oid typeNamespace,
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- /* Normal dependency from a domain to its base type's collation. */
- if (OidIsValid(typeCollation))
+ /* Normal dependency from a domain to its collation. */
+ /* We know the default collation is pinned, so don't bother recording it */
+ if (OidIsValid(typeCollation) && typeCollation != DEFAULT_COLLATION_OID)
{
referenced.classId = CollationRelationId;
referenced.objectId = typeCollation;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 53a6aafbbfb..ff84045d4fc 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -350,7 +350,8 @@ DefineIndex(RangeVar *heapRelation,
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
- ComputeIndexAttrs(indexInfo, collationObjectId, classObjectId, coloptions, attributeList,
+ ComputeIndexAttrs(indexInfo, collationObjectId, classObjectId,
+ coloptions, attributeList,
exclusionOpNames, relationId,
accessMethodName, accessMethodId,
amcanorder, isconstraint);
@@ -395,7 +396,8 @@ DefineIndex(RangeVar *heapRelation,
indexRelationId =
index_create(rel, indexRelationName, indexRelationId,
indexInfo, indexColNames,
- accessMethodId, tablespaceId, collationObjectId, classObjectId,
+ accessMethodId, tablespaceId,
+ collationObjectId, classObjectId,
coloptions, reloptions, primary,
isconstraint, deferrable, initdeferred,
allowSystemTableMods,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index bcf660b6de0..7660114ec2c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -295,7 +295,8 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu
static void ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
ColumnDef *colDef, bool isOid,
bool recurse, bool recursing, LOCKMODE lockmode);
-static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid, Oid collid);
+static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
+static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
AlterTableCmd *cmd, LOCKMODE lockmode);
static void ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
@@ -4423,7 +4424,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
/*
* Add needed dependency entries for the new column.
*/
- add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid, attribute.attcollation);
+ add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
+ add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
/*
* Propagate to children as appropriate. Unlike most other ALTER
@@ -4474,7 +4476,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
* Install a column's dependency on its datatype.
*/
static void
-add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid, Oid collid)
+add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
{
ObjectAddress myself,
referenced;
@@ -4486,9 +4488,23 @@ add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid, Oid collid)
referenced.objectId = typid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+}
+
+/*
+ * Install a column's dependency on its collation.
+ */
+static void
+add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
+{
+ ObjectAddress myself,
+ referenced;
- if (collid)
+ /* We know the default collation is pinned, so don't bother recording it */
+ if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
{
+ myself.classId = RelationRelationId;
+ myself.objectId = relid;
+ myself.objectSubId = attnum;
referenced.classId = CollationRelationId;
referenced.objectId = collid;
referenced.objectSubId = 0;
@@ -6671,7 +6687,8 @@ ATPrepAlterColumnType(List **wqueue,
else
{
transform = (Node *) makeVar(1, attnum,
- attTup->atttypid, attTup->atttypmod, attTup->attcollation,
+ attTup->atttypid, attTup->atttypmod,
+ attTup->attcollation,
0);
}
@@ -7052,7 +7069,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
/*
* Now scan for dependencies of this column on other things. The only
* thing we should find is the dependency on the column datatype, which we
- * want to remove, and possibly an associated collation.
+ * want to remove, and possibly a collation dependency.
*/
ScanKeyInit(&key[0],
Anum_pg_depend_classid,
@@ -7091,8 +7108,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
heap_close(depRel, RowExclusiveLock);
/*
- * Here we go --- change the recorded column type. (Note heapTup is a
- * copy of the syscache entry, so okay to scribble on.)
+ * Here we go --- change the recorded column type and collation. (Note
+ * heapTup is a copy of the syscache entry, so okay to scribble on.)
*/
attTup->atttypid = targettype;
attTup->atttypmod = targettypmod;
@@ -7112,8 +7129,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
heap_close(attrelation, RowExclusiveLock);
- /* Install dependency on new datatype */
- add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype, targetcollid);
+ /* Install dependencies on new datatype and collation */
+ add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
+ add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
/*
* Drop any pg_statistic entry for the column, since it's now wrong type
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 1a20b0d91be..7388e5a3db9 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -571,7 +571,7 @@ DefineType(List *names, List *parameters)
-1, /* typMod (Domains only) */
0, /* Array Dimensions of typbasetype */
false, /* Type NOT NULL */
- collation);
+ collation); /* type's collation */
/*
* Create the array type that goes with it.
@@ -611,7 +611,7 @@ DefineType(List *names, List *parameters)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- collation);
+ collation); /* type's collation */
pfree(array_type);
}
@@ -1069,7 +1069,7 @@ DefineDomain(CreateDomainStmt *stmt)
basetypeMod, /* typeMod value */
typNDims, /* Array dimensions for base type */
typNotNull, /* Type NOT NULL */
- domaincoll);
+ domaincoll); /* type's collation */
/*
* Process constraints which refer to the domain ID returned by TypeCreate
@@ -1179,7 +1179,7 @@ DefineEnum(CreateEnumStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- InvalidOid); /* typcollation */
+ InvalidOid); /* type's collation */
/* Enter the enum's values into pg_enum */
EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1219,7 +1219,7 @@ DefineEnum(CreateEnumStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- InvalidOid); /* typcollation */
+ InvalidOid); /* type's collation */
pfree(enumArrayName);
}
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 208c0fb76ac..7d27123cf05 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -170,13 +170,13 @@ typedef enum
* the two expressions from the original clause.
*
* In addition to the expressions themselves, the planner passes the btree
- * opfamily OID, btree strategy number (BTLessStrategyNumber or
+ * opfamily OID, collation OID, btree strategy number (BTLessStrategyNumber or
* BTGreaterStrategyNumber), and nulls-first flag that identify the intended
* sort ordering for each merge key. The mergejoinable operator is an
- * equality operator in this opfamily, and the two inputs are guaranteed to be
+ * equality operator in the opfamily, and the two inputs are guaranteed to be
* ordered in either increasing or decreasing (respectively) order according
- * to this opfamily, with nulls at the indicated end of the range. This
- * allows us to obtain the needed comparison function from the opfamily.
+ * to the opfamily and collation, with nulls at the indicated end of the range.
+ * This allows us to obtain the needed comparison function from the opfamily.
*/
static MergeJoinClause
MJExamineQuals(List *mergeclauses,
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 1a9540ce068..bbff4f26f8d 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -108,7 +108,8 @@ static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tidquals);
static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
Index scanrelid, Node *funcexpr, List *funccolnames,
- List *funccoltypes, List *funccoltypmods, List *funccolcollations);
+ List *funccoltypes, List *funccoltypmods,
+ List *funccolcollations);
static ValuesScan *make_valuesscan(List *qptlist, List *qpqual,
Index scanrelid, List *values_lists);
static CteScan *make_ctescan(List *qptlist, List *qpqual,
@@ -143,9 +144,9 @@ static MergeJoin *make_mergejoin(List *tlist,
bool *mergenullsfirst,
Plan *lefttree, Plan *righttree,
JoinType jointype);
-static Sort *
-make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
-AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst,
+static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
+ AttrNumber *sortColIdx, Oid *sortOperators,
+ Oid *collations, bool *nullsFirst,
double limit_tuples);
static Plan *prepare_sort_from_pathkeys(PlannerInfo *root,
Plan *lefttree, List *pathkeys,
@@ -738,7 +739,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
/* Now, insert a Sort node if subplan isn't sufficiently ordered */
if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
subplan = (Plan *) make_sort(root, subplan, numsortkeys,
- sortColIdx, sortOperators, collations, nullsFirst,
+ sortColIdx, sortOperators,
+ collations, nullsFirst,
best_path->limit_tuples);
subplans = lappend(subplans, subplan);
@@ -2013,10 +2015,10 @@ create_mergejoin_plan(PlannerInfo *root,
}
/*
- * Compute the opfamily/strategy/nullsfirst arrays needed by the executor.
- * The information is in the pathkeys for the two inputs, but we need to
- * be careful about the possibility of mergeclauses sharing a pathkey
- * (compare find_mergeclauses_for_pathkeys()).
+ * Compute the opfamily/collation/strategy/nullsfirst arrays needed by the
+ * executor. The information is in the pathkeys for the two inputs, but
+ * we need to be careful about the possibility of mergeclauses sharing a
+ * pathkey (compare find_mergeclauses_for_pathkeys()).
*/
nClauses = list_length(mergeclauses);
Assert(nClauses == list_length(best_path->path_mergeclauses));
@@ -3316,13 +3318,14 @@ make_mergejoin(List *tlist,
/*
* make_sort --- basic routine to build a Sort plan node
*
- * Caller must have built the sortColIdx, sortOperators, and nullsFirst
- * arrays already. limit_tuples is as for cost_sort (in particular, pass
- * -1 if no limit)
+ * Caller must have built the sortColIdx, sortOperators, collations, and
+ * nullsFirst arrays already.
+ * limit_tuples is as for cost_sort (in particular, pass -1 if no limit)
*/
static Sort *
make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
-AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst,
+ AttrNumber *sortColIdx, Oid *sortOperators,
+ Oid *collations, bool *nullsFirst,
double limit_tuples)
{
Sort *node = makeNode(Sort);
@@ -3378,6 +3381,11 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, Oid coll, bool nulls_first,
* values that < considers equal. We need not check nulls_first
* however because a lower-order column with the same sortop but
* opposite nulls direction is redundant.
+ *
+ * We could probably consider sort keys with the same sortop and
+ * different collations to be redundant too, but for the moment
+ * treat them as not redundant. This will be needed if we ever
+ * support collations with different notions of equality.
*/
if (sortColIdx[i] == colIdx &&
sortOperators[numCols] == sortOp &&
@@ -3410,8 +3418,9 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, Oid coll, bool nulls_first,
* 'adjust_tlist_in_place' is TRUE if lefttree must be modified in-place
*
* We must convert the pathkey information into arrays of sort key column
- * numbers and sort operator OIDs, which is the representation the executor
- * wants. These are returned into the output parameters *p_numsortkeys etc.
+ * numbers, sort operator OIDs, collation OIDs, and nulls-first flags,
+ * which is the representation the executor wants. These are returned into
+ * the output parameters *p_numsortkeys etc.
*
* If the pathkeys include expressions that aren't simple Vars, we will
* usually need to add resjunk items to the input plan's targetlist to
@@ -3610,7 +3619,8 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
pathkey->pk_eclass->ec_collation,
pathkey->pk_nulls_first,
numsortkeys,
- sortColIdx, sortOperators, collations, nullsFirst);
+ sortColIdx, sortOperators,
+ collations, nullsFirst);
}
Assert(numsortkeys > 0);
@@ -3655,7 +3665,8 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
/* Now build the Sort node */
return make_sort(root, lefttree, numsortkeys,
- sortColIdx, sortOperators, collations, nullsFirst, limit_tuples);
+ sortColIdx, sortOperators, collations,
+ nullsFirst, limit_tuples);
}
/*
@@ -3701,13 +3712,15 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
exprCollation((Node *) tle->expr),
sortcl->nulls_first,
numsortkeys,
- sortColIdx, sortOperators, collations, nullsFirst);
+ sortColIdx, sortOperators,
+ collations, nullsFirst);
}
Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys,
- sortColIdx, sortOperators, collations, nullsFirst, -1.0);
+ sortColIdx, sortOperators, collations,
+ nullsFirst, -1.0);
}
/*
@@ -3763,14 +3776,16 @@ make_sort_from_groupcols(PlannerInfo *root,
exprCollation((Node *) tle->expr),
grpcl->nulls_first,
numsortkeys,
- sortColIdx, sortOperators, collations, nullsFirst);
+ sortColIdx, sortOperators,
+ collations, nullsFirst);
grpno++;
}
Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys,
- sortColIdx, sortOperators, collations, nullsFirst, -1.0);
+ sortColIdx, sortOperators, collations,
+ nullsFirst, -1.0);
}
static Material *
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index f2b586d19cc..493bc86299f 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -281,7 +281,7 @@ SS_assign_special_param(PlannerInfo *root)
}
/*
- * Get the datatype of the first column of the plan's output.
+ * Get the datatype/typmod/collation of the first column of the plan's output.
*
* This information is stored for ARRAY_SUBLINK execution and for
* exprType()/exprTypmod()/exprCollation(), which have no way to get at the
@@ -290,7 +290,8 @@ SS_assign_special_param(PlannerInfo *root)
* always.
*/
static void
-get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod, Oid *colcollation)
+get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod,
+ Oid *colcollation)
{
/* In cases such as EXISTS, tlist might be empty; arbitrarily use VOID */
if (plan->targetlist)
@@ -478,7 +479,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks,
splan->subLinkType = subLinkType;
splan->testexpr = NULL;
splan->paramIds = NIL;
- get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod, &splan->firstColCollation);
+ get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
+ &splan->firstColCollation);
splan->useHashTable = false;
splan->unknownEqFalse = unknownEqFalse;
splan->setParam = NIL;
@@ -976,7 +978,8 @@ SS_process_ctes(PlannerInfo *root)
splan->subLinkType = CTE_SUBLINK;
splan->testexpr = NULL;
splan->paramIds = NIL;
- get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod, &splan->firstColCollation);
+ get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
+ &splan->firstColCollation);
splan->useHashTable = false;
splan->unknownEqFalse = false;
splan->setParam = NIL;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 4947a7d837e..b2032870477 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1357,9 +1357,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
/*
* Generate dummy targetlist for outer query using column names of
- * leftmost select and common datatypes of topmost set operation. Also
- * make lists of the dummy vars and their names for use in parsing ORDER
- * BY.
+ * leftmost select and common datatypes/collations of topmost set
+ * operation. Also make lists of the dummy vars and their names for use
+ * in parsing ORDER BY.
*
* Note: we use leftmostRTI as the varno of the dummy variables. It
* shouldn't matter too much which RT index they have, as long as they
@@ -1371,7 +1371,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
targetnames = NIL;
left_tlist = list_head(leftmostQuery->targetList);
- forthree(lct, sostmt->colTypes, lcm, sostmt->colTypmods, lcc, sostmt->colCollations)
+ forthree(lct, sostmt->colTypes,
+ lcm, sostmt->colTypmods,
+ lcc, sostmt->colCollations)
{
Oid colType = lfirst_oid(lct);
int32 colTypmod = lfirst_int(lcm);
diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c
index 41097263b41..ec6afd83b6c 100644
--- a/src/backend/parser/parse_cte.c
+++ b/src/backend/parser/parse_cte.c
@@ -286,10 +286,10 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
else
{
/*
- * Verify that the previously determined output column types match
- * what the query really produced. We have to check this because the
- * recursive term could have overridden the non-recursive term, and we
- * don't have any easy way to fix that.
+ * Verify that the previously determined output column types and
+ * collations match what the query really produced. We have to check
+ * this because the recursive term could have overridden the
+ * non-recursive term, and we don't have any easy way to fix that.
*/
ListCell *lctlist,
*lctyp,
@@ -366,11 +366,11 @@ analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
Assert(cte->ctecolnames == NIL);
/*
- * We need to determine column names and types. The alias column names
- * override anything coming from the query itself. (Note: the SQL spec
- * says that the alias list must be empty or exactly as long as the output
- * column set; but we allow it to be shorter for consistency with Alias
- * handling.)
+ * We need to determine column names, types, and collations. The alias
+ * column names override anything coming from the query itself. (Note:
+ * the SQL spec says that the alias list must be empty or exactly as long
+ * as the output column set; but we allow it to be shorter for consistency
+ * with Alias handling.)
*/
cte->ctecolnames = copyObject(cte->aliascolnames);
cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 2a94f73a9ab..5359e691dd1 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1174,7 +1174,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
eref->colnames = lappend(eref->colnames, makeString(attrname));
rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod);
- rte->funccolcollations = lappend_oid(rte->funccolcollations, attrcollation);
+ rte->funccolcollations = lappend_oid(rte->funccolcollations,
+ attrcollation);
}
}
else
@@ -1902,7 +1903,8 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref,
Var *varnode;
varnode = makeVar(rtindex, attr->attnum,
- attr->atttypid, attr->atttypmod, attr->attcollation,
+ attr->atttypid, attr->atttypmod,
+ attr->attcollation,
sublevels_up);
varnode->location = location;
@@ -2009,7 +2011,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
/*
* get_rte_attribute_type
- * Get attribute type information from a RangeTblEntry
+ * Get attribute type/typmod/collation information from a RangeTblEntry
*/
void
get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 3f630147b0f..e6f9e36bbca 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -372,7 +372,7 @@ transformAssignedExpr(ParseState *pstate,
Oid type_id; /* type of value provided */
Oid attrtype; /* type of target column */
int32 attrtypmod;
- Oid attrcollation;
+ Oid attrcollation; /* collation of target column */
Relation rd = pstate->p_target_relation;
Assert(rd != NULL);
@@ -388,11 +388,12 @@ transformAssignedExpr(ParseState *pstate,
/*
* If the expression is a DEFAULT placeholder, insert the attribute's
- * type/typmod into it so that exprType will report the right things. (We
- * expect that the eventually substituted default expression will in fact
- * have this type and typmod.) Also, reject trying to update a subfield
- * or array element with DEFAULT, since there can't be any default for
- * portions of a column.
+ * type/typmod/collation into it so that exprType etc will report the
+ * right things. (We expect that the eventually substituted default
+ * expression will in fact have this type and typmod. The collation
+ * likely doesn't matter, but let's set it correctly anyway.) Also,
+ * reject trying to update a subfield or array element with DEFAULT, since
+ * there can't be any default for portions of a column.
*/
if (expr && IsA(expr, SetToDefault))
{
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index e436a1ee59f..3ab90cb7d88 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -235,7 +235,8 @@ static void get_from_clause_item(Node *jtnode, Query *query,
deparse_context *context);
static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
deparse_context *context);
-static void get_from_clause_coldeflist(List *names, List *types, List *typmods, List *collations,
+static void get_from_clause_coldeflist(List *names,
+ List *types, List *typmods, List *collations,
deparse_context *context);
static void get_opclass_name(Oid opclass, Oid actual_datatype,
StringInfo buf);
@@ -6617,7 +6618,8 @@ get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
* responsible for ensuring that an alias or AS is present before it.
*/
static void
-get_from_clause_coldeflist(List *names, List *types, List *typmods, List *collations,
+get_from_clause_coldeflist(List *names,
+ List *types, List *typmods, List *collations,
deparse_context *context)
{
StringInfo buf = context->buf;
@@ -6651,7 +6653,8 @@ get_from_clause_coldeflist(List *names, List *types, List *typmods, List *collat
appendStringInfo(buf, "%s %s",
quote_identifier(attname),
format_type_with_typemod(atttypid, atttypmod));
- if (attcollation && attcollation != DEFAULT_COLLATION_OID)
+ if (OidIsValid(attcollation) &&
+ attcollation != get_typcollation(atttypid))
appendStringInfo(buf, " COLLATE %s",
generate_collation_name(attcollation));
i++;
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 2b5e37e2f05..75f510c1643 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -277,7 +277,7 @@ static const struct cachedesc cacheinfo[] = {
Anum_pg_collation_collnamespace,
0
},
- 256
+ 64
},
{CollationRelationId, /* COLLOID */
CollationOidIndexId,
@@ -288,7 +288,7 @@ static const struct cachedesc cacheinfo[] = {
0,
0
},
- 256
+ 64
},
{ConversionRelationId, /* CONDEFAULT */
ConversionDefaultIndexId,