diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 11e14f96c5..e006633b39 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.150 2009/06/11 14:48:59 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.150.2.1 2009/11/16 18:04:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -101,6 +101,10 @@ static Var *search_indexed_tlist_for_var(Var *var, static Var *search_indexed_tlist_for_non_var(Node *node, indexed_tlist *itlist, Index newvarno); +static Var *search_indexed_tlist_for_sortgroupref(Node *node, + Index sortgroupref, + indexed_tlist *itlist, + Index newvarno); static List *fix_join_expr(PlannerGlobal *glob, List *clauses, indexed_tlist *outer_itlist, @@ -1119,10 +1123,25 @@ set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset) TargetEntry *tle = (TargetEntry *) lfirst(l); Node *newexpr; - newexpr = fix_upper_expr(glob, - (Node *) tle->expr, - subplan_itlist, - rtoffset); + /* If it's a non-Var sort/group item, first try to match by sortref */ + if (tle->ressortgroupref != 0 && !IsA(tle->expr, Var)) + { + newexpr = (Node *) + search_indexed_tlist_for_sortgroupref((Node *) tle->expr, + tle->ressortgroupref, + subplan_itlist, + OUTER); + if (!newexpr) + newexpr = fix_upper_expr(glob, + (Node *) tle->expr, + subplan_itlist, + rtoffset); + } + else + newexpr = fix_upper_expr(glob, + (Node *) tle->expr, + subplan_itlist, + rtoffset); tle = flatCopyTargetEntry(tle); tle->expr = (Expr *) newexpr; output_targetlist = lappend(output_targetlist, tle); @@ -1366,6 +1385,49 @@ search_indexed_tlist_for_non_var(Node *node, return NULL; /* no match */ } +/* + * search_indexed_tlist_for_sortgroupref --- find a sort/group expression + * (which is assumed not to be just a Var) + * + * If a match is found, return a Var constructed to reference the tlist item. + * If no match, return NULL. + * + * This is needed to ensure that we select the right subplan TLE in cases + * where there are multiple textually-equal()-but-volatile sort expressions. + * And it's also faster than search_indexed_tlist_for_non_var. + */ +static Var * +search_indexed_tlist_for_sortgroupref(Node *node, + Index sortgroupref, + indexed_tlist *itlist, + Index newvarno) +{ + ListCell *lc; + + foreach(lc, itlist->tlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(lc); + + /* The equal() check should be redundant, but let's be paranoid */ + if (tle->ressortgroupref == sortgroupref && + equal(node, tle->expr)) + { + /* Found a matching subplan output expression */ + Var *newvar; + + newvar = makeVar(newvarno, + tle->resno, + exprType((Node *) tle->expr), + exprTypmod((Node *) tle->expr), + 0); + newvar->varnoold = 0; /* wasn't ever a plain Var */ + newvar->varoattno = 0; + return newvar; + } + } + return NULL; /* no match */ +} + /* * fix_join_expr * Create a new set of targetlist entries or join qual clauses by