Commit 9e9b9ac7 authored by Tom Lane's avatar Tom Lane

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().
parent 0cfdc1c6
...@@ -2159,8 +2159,8 @@ ...@@ -2159,8 +2159,8 @@
(<structfield>collname</>, <structfield>collnamespace</>). (<structfield>collname</>, <structfield>collnamespace</>).
<productname>PostgreSQL</productname> generally ignores all <productname>PostgreSQL</productname> generally ignores all
collations that do not have <structfield>collencoding</> equal to collations that do not have <structfield>collencoding</> equal to
either the current database's encoding or -1, and creation of new either the current database's encoding or -1, and creation of new entries
entries matching an entry with <structfield>collencoding</> = -1 with the same name as an entry with <structfield>collencoding</> = -1
is forbidden. Therefore it is sufficient to use a qualified SQL name is forbidden. Therefore it is sufficient to use a qualified SQL name
(<replaceable>schema</>.<replaceable>name</>) to identify a collation, (<replaceable>schema</>.<replaceable>name</>) to identify a collation,
even though this is not unique according to the catalog definition. even though this is not unique according to the catalog definition.
...@@ -6138,8 +6138,8 @@ ...@@ -6138,8 +6138,8 @@
of the type. If the type does not support collations, this will of the type. If the type does not support collations, this will
be zero. A base type that supports collations will have be zero. A base type that supports collations will have
<symbol>DEFAULT_COLLATION_OID</symbol> here. A domain over a <symbol>DEFAULT_COLLATION_OID</symbol> here. A domain over a
collatable type can have some other collation OID, if one was defined collatable type can have some other collation OID, if one was
for the domain. specified for the domain.
</para></entry> </para></entry>
</row> </row>
......
...@@ -1004,12 +1004,11 @@ SELECT am.amname AS index_method, ...@@ -1004,12 +1004,11 @@ SELECT am.amname AS index_method,
<sect1 id="indexes-collations"> <sect1 id="indexes-collations">
<title>Collations and Indexes</title> <title>Indexes and Collations</title>
<para> <para>
An index can only support one collation for one column or An index can support only one collation per index column.
expression. If multiple collations are of interest, multiple If multiple collations are of interest, multiple indexes may be needed.
indexes may be created.
</para> </para>
<para> <para>
...@@ -1022,23 +1021,21 @@ CREATE TABLE test1c ( ...@@ -1022,23 +1021,21 @@ CREATE TABLE test1c (
CREATE INDEX test1c_content_index ON test1c (content); CREATE INDEX test1c_content_index ON test1c (content);
</programlisting> </programlisting>
The created index automatically follows the collation of the The index automatically uses the collation of the
underlying column, and so a query of the form underlying column. So a query of the form
<programlisting> <programlisting>
SELECT * FROM test1c WHERE content = <replaceable>constant</replaceable>; SELECT * FROM test1c WHERE content &gt; <replaceable>constant</replaceable>;
</programlisting> </programlisting>
could use the index. could use the index, because the comparison will by default use the
</para> collation of the column. However, this index cannot accelerate queries
that involve some other collation. So if queries of the form, say,
<para>
If in addition, a query of the form, say,
<programlisting> <programlisting>
SELECT * FROM test1c WHERE content &gt; <replaceable>constant</replaceable> COLLATE "y"; SELECT * FROM test1c WHERE content &gt; <replaceable>constant</replaceable> COLLATE "y";
</programlisting> </programlisting>
is of interest, an additional index could be created that supports are also of interest, an additional index could be created that supports
the <literal>"y"</literal> collation, like so: the <literal>"y"</literal> collation, like this:
<programlisting> <programlisting>
CREATE INDEX test1c_content_index ON test1c (content COLLATE "y"); CREATE INDEX test1c_content_y_index ON test1c (content COLLATE "y");
</programlisting> </programlisting>
</para> </para>
</sect1> </sect1>
......
...@@ -108,8 +108,8 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll ...@@ -108,8 +108,8 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
<listitem> <listitem>
<para> <para>
The name of an existing collation to copy. The new collation The name of an existing collation to copy. The new collation
will have the same properties as the existing one, but they will have the same properties as the existing one, but it
will become independent objects. will be an independent object.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -134,7 +134,8 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll ...@@ -134,7 +134,8 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
<title>Examples</title> <title>Examples</title>
<para> <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>): (assuming the current database encoding is <literal>UTF8</literal>):
<programlisting> <programlisting>
CREATE COLLATION french (LOCALE = 'fr_FR.utf8'); CREATE COLLATION french (LOCALE = 'fr_FR.utf8');
......
...@@ -90,7 +90,7 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea ...@@ -90,7 +90,7 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea
<para> <para>
An optional collation for the domain. If no collation is An optional collation for the domain. If no collation is
specified, the underlying data type's default collation is used. 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. is specified.
</para> </para>
</listitem> </listitem>
......
...@@ -188,9 +188,8 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ <replaceable class="parameter">name</ ...@@ -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 name of the collation to use for the index. By default,
the index uses the collation declared for the column to be the index uses the collation declared for the column to be
indexed or the result collation of the expression to be indexed or the result collation of the expression to be
indexed. Indexes with nondefault collations are indexed. Indexes with non-default collations can be useful for
available for use by queries that involve expressions using queries that involve expressions using non-default collations.
nondefault collations.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -537,6 +536,13 @@ CREATE INDEX ON films ((lower(title))); ...@@ -537,6 +536,13 @@ CREATE INDEX ON films ((lower(title)));
will choose a name, typically <literal>films_lower_idx</>.) will choose a name, typically <literal>films_lower_idx</>.)
</para> </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> <para>
To create an index with non-default sort ordering of nulls: To create an index with non-default sort ordering of nulls:
<programlisting> <programlisting>
......
...@@ -355,10 +355,10 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -355,10 +355,10 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</para> </para>
<para> <para>
If the optional If the optional boolean
parameter <replaceable class="parameter">collatable</replaceable> parameter <replaceable class="parameter">collatable</replaceable>
is true, column definitions and expressions of the type may carry 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 the <literal>COLLATE</literal> clause. It is up to the
implementations of the functions operating on the type to actually implementations of the functions operating on the type to actually
make use of the collation information; this does not happen make use of the collation information; this does not happen
......
...@@ -238,7 +238,7 @@ gmake check LANG=C ENCODING=EUC_JP ...@@ -238,7 +238,7 @@ gmake check LANG=C ENCODING=EUC_JP
</sect2> </sect2>
<sect2> <sect2>
<title>Extra tests</title> <title>Extra Tests</title>
<para> <para>
The regression test suite contains a few test files that are not The regression test suite contains a few test files that are not
...@@ -253,8 +253,8 @@ gmake check EXTRA_TESTS=numeric_big ...@@ -253,8 +253,8 @@ gmake check EXTRA_TESTS=numeric_big
<screen> <screen>
gmake check EXTRA_TESTS=collate.linux.utf8 LANG=en_US.utf8 gmake check EXTRA_TESTS=collate.linux.utf8 LANG=en_US.utf8
</screen> </screen>
This test works only on Linux/glibc platforms and when run in a The <literal>collate.linux.utf8</> test works only on Linux/glibc
UTF-8 locale. platforms, and only when run in a locale that uses UTF-8 encoding.
</para> </para>
</sect2> </sect2>
</sect1> </sect1>
......
...@@ -360,6 +360,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) ...@@ -360,6 +360,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
return false; return false;
if (attr1->attinhcount != attr2->attinhcount) if (attr1->attinhcount != attr2->attinhcount)
return false; return false;
if (attr1->attcollation != attr2->attcollation)
return false;
/* attacl and attoptions are not even present... */ /* attacl and attoptions are not even present... */
} }
...@@ -611,7 +613,9 @@ BuildDescForRelation(List *schema) ...@@ -611,7 +613,9 @@ BuildDescForRelation(List *schema)
* BuildDescFromLists * BuildDescFromLists
* *
* Build a TupleDesc given lists of column names (as String nodes), * 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 * This is essentially a cut-down version of BuildDescForRelation for use
* with functions returning RECORD. * with functions returning RECORD.
......
...@@ -2227,14 +2227,16 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2227,14 +2227,16 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_COLLATION: case OCLASS_COLLATION:
{ {
HeapTuple collTup; HeapTuple collTup;
Form_pg_collation coll;
collTup = SearchSysCache1(COLLOID, collTup = SearchSysCache1(COLLOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(collTup)) if (!HeapTupleIsValid(collTup))
elog(ERROR, "cache lookup failed for collation %u", elog(ERROR, "cache lookup failed for collation %u",
object->objectId); object->objectId);
coll = (Form_pg_collation) GETSTRUCT(collTup);
appendStringInfo(&buffer, _("collation %s"), appendStringInfo(&buffer, _("collation %s"),
NameStr(((Form_pg_collation) GETSTRUCT(collTup))->collname)); NameStr(coll->collname));
ReleaseSysCache(collTup); ReleaseSysCache(collTup);
break; break;
} }
......
...@@ -644,7 +644,7 @@ AddNewAttributeTuples(Oid new_rel_oid, ...@@ -644,7 +644,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
/* /*
* First we add the user attributes. This is also a convenient place to * 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++) for (i = 0; i < natts; i++)
{ {
...@@ -666,7 +666,9 @@ AddNewAttributeTuples(Oid new_rel_oid, ...@@ -666,7 +666,9 @@ AddNewAttributeTuples(Oid new_rel_oid,
referenced.objectSubId = 0; referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); 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.classId = CollationRelationId;
referenced.objectId = attr->attcollation; referenced.objectId = attr->attcollation;
...@@ -921,7 +923,7 @@ AddNewRelationType(const char *typeName, ...@@ -921,7 +923,7 @@ AddNewRelationType(const char *typeName,
-1, /* typmod */ -1, /* typmod */
0, /* array dimensions for typBaseType */ 0, /* array dimensions for typBaseType */
false, /* Type NOT NULL */ false, /* Type NOT NULL */
InvalidOid); /* typcollation */ InvalidOid); /* rowtypes never have a collation */
} }
/* -------------------------------- /* --------------------------------
...@@ -1183,7 +1185,7 @@ heap_create_with_catalog(const char *relname, ...@@ -1183,7 +1185,7 @@ heap_create_with_catalog(const char *relname,
-1, /* typmod */ -1, /* typmod */
0, /* array dimensions for typBaseType */ 0, /* array dimensions for typBaseType */
false, /* Type NOT NULL */ false, /* Type NOT NULL */
InvalidOid); /* typcollation */ InvalidOid); /* rowtypes never have a collation */
pfree(relarrayname); pfree(relarrayname);
} }
......
...@@ -351,7 +351,6 @@ ConstructTupleDescriptor(Relation heapRelation, ...@@ -351,7 +351,6 @@ ConstructTupleDescriptor(Relation heapRelation,
to->atthasdef = false; to->atthasdef = false;
to->attislocal = true; to->attislocal = true;
to->attinhcount = 0; to->attinhcount = 0;
to->attcollation = collationObjectId[i]; to->attcollation = collationObjectId[i];
} }
else else
...@@ -388,7 +387,6 @@ ConstructTupleDescriptor(Relation heapRelation, ...@@ -388,7 +387,6 @@ ConstructTupleDescriptor(Relation heapRelation,
to->attcacheoff = -1; to->attcacheoff = -1;
to->atttypmod = -1; to->atttypmod = -1;
to->attislocal = true; to->attislocal = true;
to->attcollation = collationObjectId[i]; to->attcollation = collationObjectId[i];
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
...@@ -653,6 +651,7 @@ UpdateIndexRelation(Oid indexoid, ...@@ -653,6 +651,7 @@ UpdateIndexRelation(Oid indexoid,
* indexColNames: column names to use for index (List of char *) * indexColNames: column names to use for index (List of char *)
* accessMethodObjectId: OID of index AM to use * accessMethodObjectId: OID of index AM to use
* tableSpaceId: OID of tablespace 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 * classObjectId: array of index opclass OIDs, one per index column
* coloptions: array of per-index-column indoption settings * coloptions: array of per-index-column indoption settings
* reloptions: AM-specific options * reloptions: AM-specific options
...@@ -871,7 +870,8 @@ index_create(Relation heapRelation, ...@@ -871,7 +870,8 @@ index_create(Relation heapRelation,
* ---------------- * ----------------
*/ */
UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo, UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo,
collationObjectId, classObjectId, coloptions, isprimary, is_exclusion, collationObjectId, classObjectId, coloptions,
isprimary, is_exclusion,
!deferrable, !deferrable,
!concurrent); !concurrent);
...@@ -965,9 +965,11 @@ index_create(Relation heapRelation, ...@@ -965,9 +965,11 @@ index_create(Relation heapRelation,
} }
/* Store dependency on collations */ /* Store dependency on collations */
/* The default collation is pinned, so don't bother recording it */
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) 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.classId = CollationRelationId;
referenced.objectId = collationObjectId[i]; referenced.objectId = collationObjectId[i];
...@@ -2445,8 +2447,8 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot) ...@@ -2445,8 +2447,8 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples; ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
ivinfo.strategy = NULL; ivinfo.strategy = NULL;
state.tuplesort = tuplesort_begin_datum(TIDOID, state.tuplesort = tuplesort_begin_datum(TIDOID, TIDLessOperator,
TIDLessOperator, InvalidOid, false, InvalidOid, false,
maintenance_work_mem, maintenance_work_mem,
false); false);
state.htups = state.itups = state.tups_inserted = 0; state.htups = state.itups = state.tups_inserted = 0;
......
...@@ -643,8 +643,9 @@ GenerateTypeDependencies(Oid typeNamespace, ...@@ -643,8 +643,9 @@ GenerateTypeDependencies(Oid typeNamespace,
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
} }
/* Normal dependency from a domain to its base type's collation. */ /* Normal dependency from a domain to its collation. */
if (OidIsValid(typeCollation)) /* We know the default collation is pinned, so don't bother recording it */
if (OidIsValid(typeCollation) && typeCollation != DEFAULT_COLLATION_OID)
{ {
referenced.classId = CollationRelationId; referenced.classId = CollationRelationId;
referenced.objectId = typeCollation; referenced.objectId = typeCollation;
......
...@@ -350,7 +350,8 @@ DefineIndex(RangeVar *heapRelation, ...@@ -350,7 +350,8 @@ DefineIndex(RangeVar *heapRelation,
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16)); coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
ComputeIndexAttrs(indexInfo, collationObjectId, classObjectId, coloptions, attributeList, ComputeIndexAttrs(indexInfo, collationObjectId, classObjectId,
coloptions, attributeList,
exclusionOpNames, relationId, exclusionOpNames, relationId,
accessMethodName, accessMethodId, accessMethodName, accessMethodId,
amcanorder, isconstraint); amcanorder, isconstraint);
...@@ -395,7 +396,8 @@ DefineIndex(RangeVar *heapRelation, ...@@ -395,7 +396,8 @@ DefineIndex(RangeVar *heapRelation,
indexRelationId = indexRelationId =
index_create(rel, indexRelationName, indexRelationId, index_create(rel, indexRelationName, indexRelationId,
indexInfo, indexColNames, indexInfo, indexColNames,
accessMethodId, tablespaceId, collationObjectId, classObjectId, accessMethodId, tablespaceId,
collationObjectId, classObjectId,
coloptions, reloptions, primary, coloptions, reloptions, primary,
isconstraint, deferrable, initdeferred, isconstraint, deferrable, initdeferred,
allowSystemTableMods, allowSystemTableMods,
......
...@@ -295,7 +295,8 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu ...@@ -295,7 +295,8 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu
static void ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, static void ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
ColumnDef *colDef, bool isOid, ColumnDef *colDef, bool isOid,
bool recurse, bool recursing, LOCKMODE lockmode); 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, static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
AlterTableCmd *cmd, LOCKMODE lockmode); AlterTableCmd *cmd, LOCKMODE lockmode);
static void ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode); static void ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
...@@ -4423,7 +4424,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ...@@ -4423,7 +4424,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
/* /*
* Add needed dependency entries for the new column. * 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 * Propagate to children as appropriate. Unlike most other ALTER
...@@ -4474,7 +4476,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ...@@ -4474,7 +4476,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
* Install a column's dependency on its datatype. * Install a column's dependency on its datatype.
*/ */
static void 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, ObjectAddress myself,
referenced; referenced;
...@@ -4486,9 +4488,23 @@ add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid, Oid collid) ...@@ -4486,9 +4488,23 @@ add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid, Oid collid)
referenced.objectId = typid; referenced.objectId = typid;
referenced.objectSubId = 0; referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); 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.classId = CollationRelationId;
referenced.objectId = collid; referenced.objectId = collid;
referenced.objectSubId = 0; referenced.objectSubId = 0;
...@@ -6671,7 +6687,8 @@ ATPrepAlterColumnType(List **wqueue, ...@@ -6671,7 +6687,8 @@ ATPrepAlterColumnType(List **wqueue,
else else
{ {
transform = (Node *) makeVar(1, attnum, transform = (Node *) makeVar(1, attnum,
attTup->atttypid, attTup->atttypmod, attTup->attcollation, attTup->atttypid, attTup->atttypmod,
attTup->attcollation,
0); 0);
} }
...@@ -7052,7 +7069,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -7052,7 +7069,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
/* /*
* Now scan for dependencies of this column on other things. The only * 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 * 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], ScanKeyInit(&key[0],
Anum_pg_depend_classid, Anum_pg_depend_classid,
...@@ -7091,8 +7108,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -7091,8 +7108,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
heap_close(depRel, RowExclusiveLock); heap_close(depRel, RowExclusiveLock);
/* /*
* Here we go --- change the recorded column type. (Note heapTup is a * Here we go --- change the recorded column type and collation. (Note
* copy of the syscache entry, so okay to scribble on.) * heapTup is a copy of the syscache entry, so okay to scribble on.)
*/ */
attTup->atttypid = targettype; attTup->atttypid = targettype;
attTup->atttypmod = targettypmod; attTup->atttypmod = targettypmod;
...@@ -7112,8 +7129,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -7112,8 +7129,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
heap_close(attrelation, RowExclusiveLock); heap_close(attrelation, RowExclusiveLock);
/* Install dependency on new datatype */ /* Install dependencies on new datatype and collation */
add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype, targetcollid); 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 * Drop any pg_statistic entry for the column, since it's now wrong type
......
...@@ -571,7 +571,7 @@ DefineType(List *names, List *parameters) ...@@ -571,7 +571,7 @@ DefineType(List *names, List *parameters)
-1, /* typMod (Domains only) */ -1, /* typMod (Domains only) */
0, /* Array Dimensions of typbasetype */ 0, /* Array Dimensions of typbasetype */
false, /* Type NOT NULL */ false, /* Type NOT NULL */
collation); collation); /* type's collation */
/* /*
* Create the array type that goes with it. * Create the array type that goes with it.
...@@ -611,7 +611,7 @@ DefineType(List *names, List *parameters) ...@@ -611,7 +611,7 @@ DefineType(List *names, List *parameters)
-1, /* typMod (Domains only) */ -1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */ 0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */ false, /* Type NOT NULL */
collation); collation); /* type's collation */
pfree(array_type); pfree(array_type);
} }
...@@ -1069,7 +1069,7 @@ DefineDomain(CreateDomainStmt *stmt) ...@@ -1069,7 +1069,7 @@ DefineDomain(CreateDomainStmt *stmt)
basetypeMod, /* typeMod value */ basetypeMod, /* typeMod value */
typNDims, /* Array dimensions for base type */ typNDims, /* Array dimensions for base type */
typNotNull, /* Type NOT NULL */ typNotNull, /* Type NOT NULL */
domaincoll); domaincoll); /* type's collation */
/* /*
* Process constraints which refer to the domain ID returned by TypeCreate * Process constraints which refer to the domain ID returned by TypeCreate
...@@ -1179,7 +1179,7 @@ DefineEnum(CreateEnumStmt *stmt) ...@@ -1179,7 +1179,7 @@ DefineEnum(CreateEnumStmt *stmt)
-1, /* typMod (Domains only) */ -1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */ 0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */ false, /* Type NOT NULL */
InvalidOid); /* typcollation */ InvalidOid); /* type's collation */
/* Enter the enum's values into pg_enum */ /* Enter the enum's values into pg_enum */
EnumValuesCreate(enumTypeOid, stmt->vals); EnumValuesCreate(enumTypeOid, stmt->vals);
...@@ -1219,7 +1219,7 @@ DefineEnum(CreateEnumStmt *stmt) ...@@ -1219,7 +1219,7 @@ DefineEnum(CreateEnumStmt *stmt)
-1, /* typMod (Domains only) */ -1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */ 0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */ false, /* Type NOT NULL */
InvalidOid); /* typcollation */ InvalidOid); /* type's collation */
pfree(enumArrayName); pfree(enumArrayName);
} }
......
...@@ -170,13 +170,13 @@ typedef enum ...@@ -170,13 +170,13 @@ typedef enum
* the two expressions from the original clause. * the two expressions from the original clause.
* *
* In addition to the expressions themselves, the planner passes the btree * 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 * BTGreaterStrategyNumber), and nulls-first flag that identify the intended
* sort ordering for each merge key. The mergejoinable operator is an * 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 * ordered in either increasing or decreasing (respectively) order according
* to this opfamily, with nulls at the indicated end of the range. This * to the opfamily and collation, with nulls at the indicated end of the range.
* allows us to obtain the needed comparison function from the opfamily. * This allows us to obtain the needed comparison function from the opfamily.
*/ */
static MergeJoinClause static MergeJoinClause
MJExamineQuals(List *mergeclauses, MJExamineQuals(List *mergeclauses,
......
...@@ -108,7 +108,8 @@ static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, ...@@ -108,7 +108,8 @@ static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tidquals); List *tidquals);
static FunctionScan *make_functionscan(List *qptlist, List *qpqual, static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
Index scanrelid, Node *funcexpr, List *funccolnames, 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, static ValuesScan *make_valuesscan(List *qptlist, List *qpqual,
Index scanrelid, List *values_lists); Index scanrelid, List *values_lists);
static CteScan *make_ctescan(List *qptlist, List *qpqual, static CteScan *make_ctescan(List *qptlist, List *qpqual,
...@@ -143,9 +144,9 @@ static MergeJoin *make_mergejoin(List *tlist, ...@@ -143,9 +144,9 @@ static MergeJoin *make_mergejoin(List *tlist,
bool *mergenullsfirst, bool *mergenullsfirst,
Plan *lefttree, Plan *righttree, Plan *lefttree, Plan *righttree,
JoinType jointype); JoinType jointype);
static Sort * static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
make_sort(PlannerInfo *root, Plan *lefttree, int numCols, AttrNumber *sortColIdx, Oid *sortOperators,
AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst, Oid *collations, bool *nullsFirst,
double limit_tuples); double limit_tuples);
static Plan *prepare_sort_from_pathkeys(PlannerInfo *root, static Plan *prepare_sort_from_pathkeys(PlannerInfo *root,
Plan *lefttree, List *pathkeys, Plan *lefttree, List *pathkeys,
...@@ -738,7 +739,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path) ...@@ -738,7 +739,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
/* Now, insert a Sort node if subplan isn't sufficiently ordered */ /* Now, insert a Sort node if subplan isn't sufficiently ordered */
if (!pathkeys_contained_in(pathkeys, subpath->pathkeys)) if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
subplan = (Plan *) make_sort(root, subplan, numsortkeys, subplan = (Plan *) make_sort(root, subplan, numsortkeys,
sortColIdx, sortOperators, collations, nullsFirst, sortColIdx, sortOperators,
collations, nullsFirst,
best_path->limit_tuples); best_path->limit_tuples);
subplans = lappend(subplans, subplan); subplans = lappend(subplans, subplan);
...@@ -2013,10 +2015,10 @@ create_mergejoin_plan(PlannerInfo *root, ...@@ -2013,10 +2015,10 @@ create_mergejoin_plan(PlannerInfo *root,
} }
/* /*
* Compute the opfamily/strategy/nullsfirst arrays needed by the executor. * Compute the opfamily/collation/strategy/nullsfirst arrays needed by the
* The information is in the pathkeys for the two inputs, but we need to * executor. The information is in the pathkeys for the two inputs, but
* be careful about the possibility of mergeclauses sharing a pathkey * we need to be careful about the possibility of mergeclauses sharing a
* (compare find_mergeclauses_for_pathkeys()). * pathkey (compare find_mergeclauses_for_pathkeys()).
*/ */
nClauses = list_length(mergeclauses); nClauses = list_length(mergeclauses);
Assert(nClauses == list_length(best_path->path_mergeclauses)); Assert(nClauses == list_length(best_path->path_mergeclauses));
...@@ -3316,13 +3318,14 @@ make_mergejoin(List *tlist, ...@@ -3316,13 +3318,14 @@ make_mergejoin(List *tlist,
/* /*
* make_sort --- basic routine to build a Sort plan node * make_sort --- basic routine to build a Sort plan node
* *
* Caller must have built the sortColIdx, sortOperators, and nullsFirst * Caller must have built the sortColIdx, sortOperators, collations, and
* arrays already. limit_tuples is as for cost_sort (in particular, pass * nullsFirst arrays already.
* -1 if no limit) * limit_tuples is as for cost_sort (in particular, pass -1 if no limit)
*/ */
static Sort * static Sort *
make_sort(PlannerInfo *root, Plan *lefttree, int numCols, 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) double limit_tuples)
{ {
Sort *node = makeNode(Sort); Sort *node = makeNode(Sort);
...@@ -3378,6 +3381,11 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, Oid coll, bool nulls_first, ...@@ -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 * values that < considers equal. We need not check nulls_first
* however because a lower-order column with the same sortop but * however because a lower-order column with the same sortop but
* opposite nulls direction is redundant. * 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 && if (sortColIdx[i] == colIdx &&
sortOperators[numCols] == sortOp && sortOperators[numCols] == sortOp &&
...@@ -3410,8 +3418,9 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, Oid coll, bool nulls_first, ...@@ -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 * '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 * We must convert the pathkey information into arrays of sort key column
* numbers and sort operator OIDs, which is the representation the executor * numbers, sort operator OIDs, collation OIDs, and nulls-first flags,
* wants. These are returned into the output parameters *p_numsortkeys etc. * 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 * 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 * 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, ...@@ -3610,7 +3619,8 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
pathkey->pk_eclass->ec_collation, pathkey->pk_eclass->ec_collation,
pathkey->pk_nulls_first, pathkey->pk_nulls_first,
numsortkeys, numsortkeys,
sortColIdx, sortOperators, collations, nullsFirst); sortColIdx, sortOperators,
collations, nullsFirst);
} }
Assert(numsortkeys > 0); Assert(numsortkeys > 0);
...@@ -3655,7 +3665,8 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, ...@@ -3655,7 +3665,8 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
/* Now build the Sort node */ /* Now build the Sort node */
return make_sort(root, lefttree, numsortkeys, 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) ...@@ -3701,13 +3712,15 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
exprCollation((Node *) tle->expr), exprCollation((Node *) tle->expr),
sortcl->nulls_first, sortcl->nulls_first,
numsortkeys, numsortkeys,
sortColIdx, sortOperators, collations, nullsFirst); sortColIdx, sortOperators,
collations, nullsFirst);
} }
Assert(numsortkeys > 0); Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys, 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, ...@@ -3763,14 +3776,16 @@ make_sort_from_groupcols(PlannerInfo *root,
exprCollation((Node *) tle->expr), exprCollation((Node *) tle->expr),
grpcl->nulls_first, grpcl->nulls_first,
numsortkeys, numsortkeys,
sortColIdx, sortOperators, collations, nullsFirst); sortColIdx, sortOperators,
collations, nullsFirst);
grpno++; grpno++;
} }
Assert(numsortkeys > 0); Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys, return make_sort(root, lefttree, numsortkeys,
sortColIdx, sortOperators, collations, nullsFirst, -1.0); sortColIdx, sortOperators, collations,
nullsFirst, -1.0);
} }
static Material * static Material *
......
...@@ -281,7 +281,7 @@ SS_assign_special_param(PlannerInfo *root) ...@@ -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 * This information is stored for ARRAY_SUBLINK execution and for
* exprType()/exprTypmod()/exprCollation(), which have no way to get at the * exprType()/exprTypmod()/exprCollation(), which have no way to get at the
...@@ -290,7 +290,8 @@ SS_assign_special_param(PlannerInfo *root) ...@@ -290,7 +290,8 @@ SS_assign_special_param(PlannerInfo *root)
* always. * always.
*/ */
static void 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 */ /* In cases such as EXISTS, tlist might be empty; arbitrarily use VOID */
if (plan->targetlist) if (plan->targetlist)
...@@ -478,7 +479,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks, ...@@ -478,7 +479,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks,
splan->subLinkType = subLinkType; splan->subLinkType = subLinkType;
splan->testexpr = NULL; splan->testexpr = NULL;
splan->paramIds = NIL; 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->useHashTable = false;
splan->unknownEqFalse = unknownEqFalse; splan->unknownEqFalse = unknownEqFalse;
splan->setParam = NIL; splan->setParam = NIL;
...@@ -976,7 +978,8 @@ SS_process_ctes(PlannerInfo *root) ...@@ -976,7 +978,8 @@ SS_process_ctes(PlannerInfo *root)
splan->subLinkType = CTE_SUBLINK; splan->subLinkType = CTE_SUBLINK;
splan->testexpr = NULL; splan->testexpr = NULL;
splan->paramIds = NIL; 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->useHashTable = false;
splan->unknownEqFalse = false; splan->unknownEqFalse = false;
splan->setParam = NIL; splan->setParam = NIL;
......
...@@ -1357,9 +1357,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1357,9 +1357,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
/* /*
* Generate dummy targetlist for outer query using column names of * Generate dummy targetlist for outer query using column names of
* leftmost select and common datatypes of topmost set operation. Also * leftmost select and common datatypes/collations of topmost set
* make lists of the dummy vars and their names for use in parsing ORDER * operation. Also make lists of the dummy vars and their names for use
* BY. * in parsing ORDER BY.
* *
* Note: we use leftmostRTI as the varno of the dummy variables. It * 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 * shouldn't matter too much which RT index they have, as long as they
...@@ -1371,7 +1371,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1371,7 +1371,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
targetnames = NIL; targetnames = NIL;
left_tlist = list_head(leftmostQuery->targetList); 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); Oid colType = lfirst_oid(lct);
int32 colTypmod = lfirst_int(lcm); int32 colTypmod = lfirst_int(lcm);
......
...@@ -286,10 +286,10 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte) ...@@ -286,10 +286,10 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
else else
{ {
/* /*
* Verify that the previously determined output column types match * Verify that the previously determined output column types and
* what the query really produced. We have to check this because the * collations match what the query really produced. We have to check
* recursive term could have overridden the non-recursive term, and we * this because the recursive term could have overridden the
* don't have any easy way to fix that. * non-recursive term, and we don't have any easy way to fix that.
*/ */
ListCell *lctlist, ListCell *lctlist,
*lctyp, *lctyp,
...@@ -366,11 +366,11 @@ analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist) ...@@ -366,11 +366,11 @@ analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
Assert(cte->ctecolnames == NIL); Assert(cte->ctecolnames == NIL);
/* /*
* We need to determine column names and types. The alias column names * We need to determine column names, types, and collations. The alias
* override anything coming from the query itself. (Note: the SQL spec * column names override anything coming from the query itself. (Note:
* says that the alias list must be empty or exactly as long as the output * the SQL spec says that the alias list must be empty or exactly as long
* column set; but we allow it to be shorter for consistency with Alias * as the output column set; but we allow it to be shorter for consistency
* handling.) * with Alias handling.)
*/ */
cte->ctecolnames = copyObject(cte->aliascolnames); cte->ctecolnames = copyObject(cte->aliascolnames);
cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL; cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
......
...@@ -1174,7 +1174,8 @@ addRangeTableEntryForFunction(ParseState *pstate, ...@@ -1174,7 +1174,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
eref->colnames = lappend(eref->colnames, makeString(attrname)); eref->colnames = lappend(eref->colnames, makeString(attrname));
rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype); rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod); rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod);
rte->funccolcollations = lappend_oid(rte->funccolcollations, attrcollation); rte->funccolcollations = lappend_oid(rte->funccolcollations,
attrcollation);
} }
} }
else else
...@@ -1902,7 +1903,8 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref, ...@@ -1902,7 +1903,8 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref,
Var *varnode; Var *varnode;
varnode = makeVar(rtindex, attr->attnum, varnode = makeVar(rtindex, attr->attnum,
attr->atttypid, attr->atttypmod, attr->attcollation, attr->atttypid, attr->atttypmod,
attr->attcollation,
sublevels_up); sublevels_up);
varnode->location = location; varnode->location = location;
...@@ -2009,7 +2011,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum) ...@@ -2009,7 +2011,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
/* /*
* get_rte_attribute_type * get_rte_attribute_type
* Get attribute type information from a RangeTblEntry * Get attribute type/typmod/collation information from a RangeTblEntry
*/ */
void void
get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
......
...@@ -372,7 +372,7 @@ transformAssignedExpr(ParseState *pstate, ...@@ -372,7 +372,7 @@ transformAssignedExpr(ParseState *pstate,
Oid type_id; /* type of value provided */ Oid type_id; /* type of value provided */
Oid attrtype; /* type of target column */ Oid attrtype; /* type of target column */
int32 attrtypmod; int32 attrtypmod;
Oid attrcollation; Oid attrcollation; /* collation of target column */
Relation rd = pstate->p_target_relation; Relation rd = pstate->p_target_relation;
Assert(rd != NULL); Assert(rd != NULL);
...@@ -388,11 +388,12 @@ transformAssignedExpr(ParseState *pstate, ...@@ -388,11 +388,12 @@ transformAssignedExpr(ParseState *pstate,
/* /*
* If the expression is a DEFAULT placeholder, insert the attribute's * If the expression is a DEFAULT placeholder, insert the attribute's
* type/typmod into it so that exprType will report the right things. (We * type/typmod/collation into it so that exprType etc will report the
* expect that the eventually substituted default expression will in fact * right things. (We expect that the eventually substituted default
* have this type and typmod.) Also, reject trying to update a subfield * expression will in fact have this type and typmod. The collation
* or array element with DEFAULT, since there can't be any default for * likely doesn't matter, but let's set it correctly anyway.) Also,
* portions of a column. * 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)) if (expr && IsA(expr, SetToDefault))
{ {
......
...@@ -235,7 +235,8 @@ static void get_from_clause_item(Node *jtnode, Query *query, ...@@ -235,7 +235,8 @@ static void get_from_clause_item(Node *jtnode, Query *query,
deparse_context *context); deparse_context *context);
static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte, static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
deparse_context *context); 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); deparse_context *context);
static void get_opclass_name(Oid opclass, Oid actual_datatype, static void get_opclass_name(Oid opclass, Oid actual_datatype,
StringInfo buf); StringInfo buf);
...@@ -6617,7 +6618,8 @@ get_from_clause_alias(Alias *alias, RangeTblEntry *rte, ...@@ -6617,7 +6618,8 @@ get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
* responsible for ensuring that an alias or AS is present before it. * responsible for ensuring that an alias or AS is present before it.
*/ */
static void 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) deparse_context *context)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
...@@ -6651,7 +6653,8 @@ get_from_clause_coldeflist(List *names, List *types, List *typmods, List *collat ...@@ -6651,7 +6653,8 @@ get_from_clause_coldeflist(List *names, List *types, List *typmods, List *collat
appendStringInfo(buf, "%s %s", appendStringInfo(buf, "%s %s",
quote_identifier(attname), quote_identifier(attname),
format_type_with_typemod(atttypid, atttypmod)); format_type_with_typemod(atttypid, atttypmod));
if (attcollation && attcollation != DEFAULT_COLLATION_OID) if (OidIsValid(attcollation) &&
attcollation != get_typcollation(atttypid))
appendStringInfo(buf, " COLLATE %s", appendStringInfo(buf, " COLLATE %s",
generate_collation_name(attcollation)); generate_collation_name(attcollation));
i++; i++;
......
...@@ -277,7 +277,7 @@ static const struct cachedesc cacheinfo[] = { ...@@ -277,7 +277,7 @@ static const struct cachedesc cacheinfo[] = {
Anum_pg_collation_collnamespace, Anum_pg_collation_collnamespace,
0 0
}, },
256 64
}, },
{CollationRelationId, /* COLLOID */ {CollationRelationId, /* COLLOID */
CollationOidIndexId, CollationOidIndexId,
...@@ -288,7 +288,7 @@ static const struct cachedesc cacheinfo[] = { ...@@ -288,7 +288,7 @@ static const struct cachedesc cacheinfo[] = {
0, 0,
0 0
}, },
256 64
}, },
{ConversionRelationId, /* CONDEFAULT */ {ConversionRelationId, /* CONDEFAULT */
ConversionDefaultIndexId, ConversionDefaultIndexId,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment