diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 7a2aaa48f6bee512fe4022d1deec563a4bcb96c3..a110fa947b1421207f3c5cf1e7f047fb8a56c803 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -11,13 +11,14 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.84 2007/04/15 20:09:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.85 2007/05/31 16:57:34 tgl Exp $ * *------------------------------------------------------------------------- */ #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, diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 605e7f64eed42188d232bdb164ca6b0d4d0bb467..70b3d7d43f5c8846259279c4180e23b12f767772 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.135 2007/05/25 17:54:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.136 2007/05/31 16:57:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index d6b13ca8e390560a123bd6df51f2b790237c11c0..4a2f264969114056a1d9d51edf87d99db89b5be7 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.143 2007/05/22 23:23:57 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.144 2007/05/31 16:57:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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? */