Make a code-cleanup pass over the collations patch.

This patch is almost entirely cosmetic --- mostly cleaning up a lot of
neglected comments, and fixing code layout problems in places where the
patch made lines too long and then pgindent did weird things with that.
I did find a bug-of-omission in equalTupleDescs().
This commit is contained in:
Tom Lane 2011-04-22 17:43:18 -04:00
parent 0cfdc1c657
commit 9e9b9ac7d1
24 changed files with 179 additions and 118 deletions

View File

@ -2159,8 +2159,8 @@
(<structfield>collname</>, <structfield>collnamespace</>).
<productname>PostgreSQL</productname> generally ignores all
collations that do not have <structfield>collencoding</> equal to
either the current database's encoding or -1, and creation of new
entries matching an entry with <structfield>collencoding</> = -1
either the current database's encoding or -1, and creation of new entries
with the same name as an entry with <structfield>collencoding</> = -1
is forbidden. Therefore it is sufficient to use a qualified SQL name
(<replaceable>schema</>.<replaceable>name</>) to identify a collation,
even though this is not unique according to the catalog definition.
@ -6138,8 +6138,8 @@
of the type. If the type does not support collations, this will
be zero. A base type that supports collations will have
<symbol>DEFAULT_COLLATION_OID</symbol> here. A domain over a
collatable type can have some other collation OID, if one was defined
for the domain.
collatable type can have some other collation OID, if one was
specified for the domain.
</para></entry>
</row>

View File

@ -1004,12 +1004,11 @@ SELECT am.amname AS index_method,
<sect1 id="indexes-collations">
<title>Collations and Indexes</title>
<title>Indexes and Collations</title>
<para>
An index can only support one collation for one column or
expression. If multiple collations are of interest, multiple
indexes may be created.
An index can support only one collation per index column.
If multiple collations are of interest, multiple indexes may be needed.
</para>
<para>
@ -1022,23 +1021,21 @@ CREATE TABLE test1c (
CREATE INDEX test1c_content_index ON test1c (content);
</programlisting>
The created index automatically follows the collation of the
underlying column, and so a query of the form
The index automatically uses the collation of the
underlying column. So a query of the form
<programlisting>
SELECT * FROM test1c WHERE content = <replaceable>constant</replaceable>;
SELECT * FROM test1c WHERE content &gt; <replaceable>constant</replaceable>;
</programlisting>
could use the index.
</para>
<para>
If in addition, a query of the form, say,
could use the index, because the comparison will by default use the
collation of the column. However, this index cannot accelerate queries
that involve some other collation. So if queries of the form, say,
<programlisting>
SELECT * FROM test1c WHERE content &gt; <replaceable>constant</replaceable> COLLATE "y";
</programlisting>
is of interest, an additional index could be created that supports
the <literal>"y"</literal> collation, like so:
are also of interest, an additional index could be created that supports
the <literal>"y"</literal> collation, like this:
<programlisting>
CREATE INDEX test1c_content_index ON test1c (content COLLATE "y");
CREATE INDEX test1c_content_y_index ON test1c (content COLLATE "y");
</programlisting>
</para>
</sect1>

View File

@ -108,8 +108,8 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
<listitem>
<para>
The name of an existing collation to copy. The new collation
will have the same properties as the existing one, but they
will become independent objects.
will have the same properties as the existing one, but it
will be an independent object.
</para>
</listitem>
</varlistentry>
@ -134,7 +134,8 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
<title>Examples</title>
<para>
To create a collation from the locale <literal>fr_FR.utf8</literal>
To create a collation from the operating system locale
<literal>fr_FR.utf8</literal>
(assuming the current database encoding is <literal>UTF8</literal>):
<programlisting>
CREATE COLLATION french (LOCALE = 'fr_FR.utf8');

View File

@ -90,7 +90,7 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea
<para>
An optional collation for the domain. If no collation is
specified, the underlying data type's default collation is used.
The underlying type must be collatable when <literal>COLLATE</>
The underlying type must be collatable if <literal>COLLATE</>
is specified.
</para>
</listitem>

View File

@ -188,9 +188,8 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ <replaceable class="parameter">name</
The name of the collation to use for the index. By default,
the index uses the collation declared for the column to be
indexed or the result collation of the expression to be
indexed. Indexes with nondefault collations are
available for use by queries that involve expressions using
nondefault collations.
indexed. Indexes with non-default collations can be useful for
queries that involve expressions using non-default collations.
</para>
</listitem>
</varlistentry>
@ -537,6 +536,13 @@ CREATE INDEX ON films ((lower(title)));
will choose a name, typically <literal>films_lower_idx</>.)
</para>
<para>
To create an index with non-default collation:
<programlisting>
CREATE INDEX title_idx_german ON films (title COLLATE "de_DE");
</programlisting>
</para>
<para>
To create an index with non-default sort ordering of nulls:
<programlisting>

View File

@ -355,10 +355,10 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</para>
<para>
If the optional
If the optional boolean
parameter <replaceable class="parameter">collatable</replaceable>
is true, column definitions and expressions of the type may carry
collation information and allow the use of
collation information through use of
the <literal>COLLATE</literal> clause. It is up to the
implementations of the functions operating on the type to actually
make use of the collation information; this does not happen

View File

@ -238,7 +238,7 @@ gmake check LANG=C ENCODING=EUC_JP
</sect2>
<sect2>
<title>Extra tests</title>
<title>Extra Tests</title>
<para>
The regression test suite contains a few test files that are not
@ -253,8 +253,8 @@ gmake check EXTRA_TESTS=numeric_big
<screen>
gmake check EXTRA_TESTS=collate.linux.utf8 LANG=en_US.utf8
</screen>
This test works only on Linux/glibc platforms and when run in a
UTF-8 locale.
The <literal>collate.linux.utf8</> test works only on Linux/glibc
platforms, and only when run in a locale that uses UTF-8 encoding.
</para>
</sect2>
</sect1>

View File

@ -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.

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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);
}
if (collid)
/*
* Install a column's dependency on its collation.
*/
static void
add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
{
ObjectAddress myself,
referenced;
/* 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

View File

@ -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);
}

View File

@ -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,

View File

@ -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 *

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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))
{

View File

@ -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++;

View File

@ -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,