diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 2ad3120369..f96d7bb555 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -11,7 +11,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.87 2007/11/02 18:54:15 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.88 2007/11/08 19:25:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -292,13 +292,14 @@ make_pathkey_from_sortinfo(PlannerInfo *root, if (exprType((Node *) expr) != opcintype && !IsPolymorphicType(opcintype)) { - /* Strip any existing RelabelType, and add a new one */ + /* Strip any existing RelabelType, and add a new one if needed */ while (expr && IsA(expr, RelabelType)) expr = (Expr *) ((RelabelType *) expr)->arg; - expr = (Expr *) makeRelabelType(expr, - opcintype, - -1, - COERCE_DONTCARE); + if (exprType((Node *) expr) != opcintype) + expr = (Expr *) makeRelabelType(expr, + opcintype, + -1, + COERCE_DONTCARE); } /* Now find or create a matching EquivalenceClass */ diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index fb9b437174..becb8255e8 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.232 2007/11/02 18:54:15 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.233 2007/11/08 19:25:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2738,7 +2738,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, /* * We can sort by any non-constant expression listed in the pathkey's * EquivalenceClass. For now, we take the first one that corresponds - * to an available Var in the tlist. If there isn't any, use the first + * to an available item in the tlist. If there isn't any, use the first * one that is an expression in the input's vars. (The non-const * restriction only matters if the EC is below_outer_join; but if it * isn't, it won't contain consts anyway, else we'd have discarded @@ -2766,24 +2766,21 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, /* * We can also use it if the pathkey expression is a relabel - * of the tlist entry. This is needed for binary-compatible - * cases (cf. make_pathkey_from_sortinfo). + * of the tlist entry, or vice versa. This is needed for + * binary-compatible cases (cf. make_pathkey_from_sortinfo). + * We prefer an exact match, though, so we do the basic + * search first. */ - if (IsA(em->em_expr, RelabelType)) + tle = tlist_member_ignore_relabel((Node *) em->em_expr, tlist); + if (tle) { - Expr *rtarg = ((RelabelType *) em->em_expr)->arg; - - tle = tlist_member((Node *) rtarg, tlist); - if (tle) - { - pk_datatype = em->em_datatype; - break; /* found expr already in tlist */ - } + pk_datatype = em->em_datatype; + break; /* found expr already in tlist */ } } if (!tle) { - /* No matching Var; look for a computable expression */ + /* No matching tlist item; look for a computable expression */ Expr *sortexpr = NULL; foreach(j, pathkey->pk_eclass->ec_members) @@ -2798,7 +2795,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, exprvars = pull_var_clause((Node *) sortexpr, false); foreach(k, exprvars) { - if (!tlist_member(lfirst(k), tlist)) + if (!tlist_member_ignore_relabel(lfirst(k), tlist)) break; } list_free(exprvars); diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index 1e507235c5..e58fe7dc7f 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.74 2007/01/05 22:19:33 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.75 2007/11/08 19:25:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,34 @@ tlist_member(Node *node, List *targetlist) return NULL; } +/* + * tlist_member_ignore_relabel + * Same as above, except that we ignore top-level RelabelType nodes + * while checking for a match. This is needed for some scenarios + * involving binary-compatible sort operations. + */ +TargetEntry * +tlist_member_ignore_relabel(Node *node, List *targetlist) +{ + ListCell *temp; + + while (node && IsA(node, RelabelType)) + node = (Node *) ((RelabelType *) node)->arg; + + foreach(temp, targetlist) + { + TargetEntry *tlentry = (TargetEntry *) lfirst(temp); + Expr *tlexpr = tlentry->expr; + + while (tlexpr && IsA(tlexpr, RelabelType)) + tlexpr = ((RelabelType *) tlexpr)->arg; + + if (equal(node, tlexpr)) + return tlentry; + } + return NULL; +} + /* * flatten_tlist * Create a target list that only contains unique variables. diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h index 31156ebcbc..bb127cbce2 100644 --- a/src/include/optimizer/tlist.h +++ b/src/include/optimizer/tlist.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/optimizer/tlist.h,v 1.45 2007/01/05 22:19:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/tlist.h,v 1.46 2007/11/08 19:25:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,7 @@ extern TargetEntry *tlist_member(Node *node, List *targetlist); +extern TargetEntry *tlist_member_ignore_relabel(Node *node, List *targetlist); extern List *flatten_tlist(List *tlist); extern List *add_to_flat_tlist(List *tlist, List *vars);