Change build_index_pathkeys() so that the expressions it builds to represent
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 31 May 2007 16:57:34 +0000 (16:57 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 31 May 2007 16:57:34 +0000 (16:57 +0000)
index key columns always have the type expected by the index's associated
operators, ie, we add RelabelType nodes when dealing with binary-compatible
index opclasses.  This is needed to get varchar indexes to play nicely with
the new EquivalenceClass machinery, as per recent gripe from Josh Berkus that
CVS HEAD was failing to match a varchar index column to a constant restriction
in the query.

It seems likely that this change will allow removal of a lot of ugly ad-hoc
RelabelType-stripping that the planner has traditionally done while matching
expressions to other expressions, but I'll worry about that some other day.

src/backend/optimizer/path/pathkeys.c
src/backend/optimizer/util/plancat.c
src/include/nodes/relation.h

index dc30a9e88f97c165c65ded11d13d539745e8c4e5..1cbef036d5f35b6cc1ca2985d8d0de7440f8d512 100644 (file)
@@ -18,6 +18,7 @@
 #include "postgres.h"
 
 #include "access/skey.h"
+#include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
 #include "nodes/plannodes.h"
 #include "optimizer/clauses.h"
@@ -493,6 +494,27 @@ build_index_pathkeys(PlannerInfo *root,
                        indexprs_item = lnext(indexprs_item);
                }
 
+               /*
+                * When dealing with binary-compatible indexes, we have to ensure that
+                * the exposed type of the expression tree matches the declared input
+                * type of the opclass, except when that is a polymorphic type
+                * (compare the behavior of parse_coerce.c).  This ensures that we can
+                * correctly match the indexkey expression to expressions we find in
+                * the query, because arguments of operators that could match the
+                * index will be cast likewise.
+                */
+               if (exprType((Node *) indexkey) != index->opcintype[i] &&
+                       !IsPolymorphicType(index->opcintype[i]))
+               {
+                       /* Strip any existing RelabelType, and add a new one */
+                       while (indexkey && IsA(indexkey, RelabelType))
+                               indexkey = (Expr *) ((RelabelType *) indexkey)->arg;
+                       indexkey = (Expr *) makeRelabelType(indexkey,
+                                                                                               index->opcintype[i],
+                                                                                               -1,
+                                                                                               COERCE_DONTCARE);
+               }
+
                /* OK, make a canonical pathkey for this sort key */
                cpathkey = make_pathkey_from_sortinfo(root,
                                                                                          indexkey,
index a15b9393f9f79144c82fc3a6c58e8f1851914711..60d6ace71fbc23850408de8ed5faf1b284f54c68 100644 (file)
@@ -171,20 +171,23 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
                        info->ncolumns = ncolumns = index->indnatts;
 
                        /*
-                        * Need to make opfamily array large enough to put a terminating
-                        * zero at the end.
+                        * Allocate per-column info arrays.  To save a few palloc cycles
+                        * we allocate all the Oid-type arrays in one request.  Note that
+                        * the opfamily array needs an extra, terminating zero at the end.
+                        * We pre-zero the ordering info in case the index is unordered.
                         */
                        info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
-                       info->opfamily = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
-                       /* initialize these to zeroes in case index is unordered */
-                       info->fwdsortop = (Oid *) palloc0(sizeof(Oid) * ncolumns);
-                       info->revsortop = (Oid *) palloc0(sizeof(Oid) * ncolumns);
+                       info->opfamily = (Oid *) palloc0(sizeof(Oid) * (4 * ncolumns + 1));
+                       info->opcintype = info->opfamily + (ncolumns + 1);
+                       info->fwdsortop = info->opcintype + ncolumns;
+                       info->revsortop = info->fwdsortop + ncolumns;
                        info->nulls_first = (bool *) palloc0(sizeof(bool) * ncolumns);
 
                        for (i = 0; i < ncolumns; i++)
                        {
-                               info->opfamily[i] = indexRelation->rd_opfamily[i];
                                info->indexkeys[i] = index->indkey.values[i];
+                               info->opfamily[i] = indexRelation->rd_opfamily[i];
+                               info->opcintype[i] = indexRelation->rd_opcintype[i];
                        }
 
                        info->relam = indexRelation->rd_rel->relam;
index 800f547e57973c5fc121b4e4f543ebf075960b73..55f1a500ade1eceb05bad7a592b47d6c0b50ec75 100644 (file)
@@ -370,10 +370,11 @@ typedef struct RelOptInfo
  *             and indexes, but that created confusion without actually doing anything
  *             useful.  So now we have a separate IndexOptInfo struct for indexes.
  *
- *             opfamily[], indexkeys[], fwdsortop[], revsortop[], and nulls_first[]
- *             each have ncolumns entries.  Note: for historical reasons, the
- *             opfamily array has an extra entry that is always zero.  Some code
- *             scans until it sees a zero entry, rather than looking at ncolumns.
+ *             opfamily[], indexkeys[], opcintype[], fwdsortop[], revsortop[],
+ *             and nulls_first[] each have ncolumns entries.
+ *             Note: for historical reasons, the opfamily array has an extra entry
+ *             that is always zero.  Some code scans until it sees a zero entry,
+ *             rather than looking at ncolumns.
  *
  *             Zeroes in the indexkeys[] array indicate index columns that are
  *             expressions; there is one element in indexprs for each such column.
@@ -402,6 +403,7 @@ typedef struct IndexOptInfo
        int                     ncolumns;               /* number of columns in index */
        Oid                *opfamily;           /* OIDs of operator families for columns */
        int                *indexkeys;          /* column numbers of index's keys, or 0 */
+       Oid                *opcintype;          /* OIDs of opclass declared input data types */
        Oid                *fwdsortop;          /* OIDs of sort operators for each column */
        Oid                *revsortop;          /* OIDs of sort operators for backward scan */
        bool       *nulls_first;        /* do NULLs come first in the sort order? */