diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-07-09 21:11:57 +0000 | 
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-07-09 21:11:57 +0000 | 
| commit | e5b8e868cd3b59660490b660627bdc1507fdda86 (patch) | |
| tree | 25333f3031d7963a28cb16239a8005aacf1d3002 /src/backend/utils/adt/ruleutils.c | |
| parent | beed55dff7e39553db94a8760862b5d8a3a92f4a (diff) | |
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.
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
| -rw-r--r-- | src/backend/utils/adt/ruleutils.c | 45 | 
1 files changed, 44 insertions, 1 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 54b6018d8e4..b0715ed247c 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.326.2.1 2010/07/09 21:11:57 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;  | 
