From 2b8a624596179efc3605cef4c80ba9fcea75c21c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 9 Jul 2010 21:11:47 +0000 Subject: [PATCH] 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 54b6018d8e..8b99c95070 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; -- 2.40.0