postgres.git / summary / log / commit / refs

commit    2b8a624596179efc3605cef4c80ba9fcea75c21c
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Fri Jul 09 21:11:47 2010 +0000
First released in: 9.1.0, 9.0.0

    Fix ruleutils' get_variable() to print something useful for Vars referencing
    resjunk outputs of subquery tlists, instead of throwing an error.  Per bug
    #5548 from Daniel Grace.
    
    We might at some point find we ought to back-patch this further than 9.0,
    but I think that such Vars can only occur as resjunk members of upper-level
    tlists, in which case the problem can't arise because prior versions didn't
    print resjunk tlist items in EXPLAIN VERBOSE.


src/backend/utils/adt/ruleutils.c | 45 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 54b6018d8e4..8b99c95070d 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.326 2010/05/30 18:10:41 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.327 2010/07/09 21:11:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3637,6 +3637,49 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context) return NULL; /* keep compiler quiet */ } + /* + * The planner will sometimes emit Vars referencing resjunk elements of a + * subquery's target list (this is currently only possible if it chooses + * to generate a "physical tlist" for a SubqueryScan or CteScan node). + * Although we prefer to print subquery-referencing Vars using the + * subquery's alias, that's not possible for resjunk items since they have + * no alias. So in that case, drill down to the subplan and print the + * contents of the referenced tlist item. This works because in a plan + * tree, such Vars can only occur in a SubqueryScan or CteScan node, + * and we'll have set dpns->inner_plan to reference the child plan node. + */ + if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) && + attnum > list_length(rte->eref->colnames) && + dpns->inner_plan) + { + TargetEntry *tle; + Plan *save_outer; + Plan *save_inner; + + tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno); + if (!tle) + elog(ERROR, "bogus varattno for subquery var: %d", var->varattno); + + Assert(netlevelsup == 0); + save_outer = dpns->outer_plan; + save_inner = dpns->inner_plan; + push_plan(dpns, dpns->inner_plan); + + /* + * Force parentheses because our caller probably assumed a Var is a + * simple expression. + */ + if (!IsA(tle->expr, Var)) + appendStringInfoChar(buf, '('); + get_rule_expr((Node *) tle->expr, context, true); + if (!IsA(tle->expr, Var)) + appendStringInfoChar(buf, ')'); + + dpns->outer_plan = save_outer; + dpns->inner_plan = save_inner; + return NULL; + } + /* Identify names to use */ schemaname = NULL; /* default assumptions */ refname = rte->eref->aliasname; [parent: a0d7c5f6894f]