Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Make a code-cleanup pass over the collations patch.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Apr 2011 21:43:18 +0000 (17:43 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Apr 2011 21:43:18 +0000 (17:43 -0400)
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().

24 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/indices.sgml
doc/src/sgml/ref/create_collation.sgml
doc/src/sgml/ref/create_domain.sgml
doc/src/sgml/ref/create_index.sgml
doc/src/sgml/ref/create_type.sgml
doc/src/sgml/regress.sgml
src/backend/access/common/tupdesc.c
src/backend/catalog/dependency.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/pg_type.c
src/backend/commands/indexcmds.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/nodeMergejoin.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/subselect.c
src/backend/parser/analyze.c
src/backend/parser/parse_cte.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/syscache.c

index d0a8dc72cb60af4f85d7afc8de9c636aae4130b6..7b62818ce4b78cfab607d44bf958d816716cb3d0 100644 (file)
    (<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.
        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>
 
index 15fbe0d614e7b8854c524c9334dbe8f7321b9877..2dedb153c067a46995164b76491bd0421a728cbe 100644 (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>
index fc79225001164af9cc8b1dad0eddde8dd403bd0a..c85357681436cad35e280c219650b6184c5ed32c 100644 (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');
index 2300edefe3a0d8acc7d98170b2aa4560138b0a54..8db90f911f6194f2547287d082e944a3c8c6c9bc 100644 (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>
index 8ec7abbbd495231552751063a72925a73bee94df..43b6499603cb0c28f5e421a099c679df21541f87 100644 (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>
index 98e1764b1e917ef40eeaefd5660ca20c556f9a38..70b0325f0ec376b3cc573cb66cce07e1fb2a1267 100644 (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
index 874d45615e2cdc2b4172227ce823a979f3e76b48..bb5f577852c8691765955d599b41524d25437884 100644 (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>
index c06a0271ca59104e1c458fc0dcc39b493ee9f96d..16979c4ea722c215846c4b8152c09265994eff0b 100644 (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.
index b3ed946530ef741058bdce5a4218860e22802ec9..c459c1e221383b47a6d4b21178b6b4d9e9b5f471 100644 (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;
            }
index 8c5670fdb8c49a041a7235a4f1e899aa4d865318..28d5c549a32d3eff46dd39ca391a90e1437c93f5 100644 (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);
    }
index c79402c72a99ade30c4fad10640a5537c0a7007c..bc630a6f3ac9e9a3f3bc45e08e70563b9ae2960e 100644 (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;
index 9e35e73f9cf9349565f206b67d2c8bb27130df8a..b6912578786060b4da2bc94eb682b54b64db8215 100644 (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;
index 53a6aafbbfb996e65ed5393e60d8533bfb9e8c7a..ff84045d4fc4d69e42c0bb8cc367eae1e2927753 100644 (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,
index bcf660b6de02f139f71d294aaef2d455e8940db8..7660114ec2ce41b050c7cbe2aa44fc0c99abfa1d 100644 (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);
+}
+
+/*
+ * 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
index 1a20b0d91be78ccfa3dc535eb817a8073a837666..7388e5a3db9167a5b82cdb9c942dd170c30fa47d 100644 (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);
 }
index 208c0fb76ac11941dc583e89e31bf6a6e92d1d9b..7d27123cf058ab48bd9bdd7a43d2bbcba0fc5739 100644 (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,
index 1a9540ce06802f913810ce0d81a1d5ffaaed9d72..bbff4f26f8d6b93456eb3ad5175cbba1f65353ad 100644 (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 *
index f2b586d19cc99c241b0682e2e6d493de3c7124fe..493bc86299f16bcbd05e999a1fdccd88af65f82a 100644 (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;
index 4947a7d837e693e86ed0e19e03d3971eea5b64df..b2032870477cdd7181e1a21fe72cd8bfdb272f8a 100644 (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);
index 41097263b413f79b1fa2ea2fcd448e88edd3b4ef..ec6afd83b6c3977f45ce150f00b529b528bcbf48 100644 (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;
index 2a94f73a9abd284c406aee655b43cb34cbf89bb9..5359e691dd17bee35d07913895b90b0ce8a75c1a 100644 (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,
index 3f630147b0fa5687c7df6ea63f747cc7a16ee3e5..e6f9e36bbcadfc1a79eca45bfb30627d0e321ba7 100644 (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))
    {
index e436a1ee59ff63d9718ec9dfa4905112b5aa90b3..3ab90cb7d884989924d22e8bfd01c59eccd9895a 100644 (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++;
index 2b5e37e2f058db895de9bdb2d88400815c10c31b..75f510c16434380b05eecc1215cb09fc0030bdad 100644 (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,