From c876d965f5e7a8b300f57d21de570cca291ac84a Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 30 Dec 2005 18:34:22 +0000
Subject: [PATCH] Repair EXPLAIN failure when trying to display a plan
 condition that involves selection of a field from the result of a function
 returning RECORD. I believe this case is new in 8.1; it's due to the addition
 of OUT parameters. Per example from Michael Fuhr.

---
 src/backend/utils/adt/ruleutils.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index eaf4f195077..7c47054633f 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.211 2005/12/28 01:30:00 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.212 2005/12/30 18:34:22 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -1525,8 +1525,15 @@ deparse_context_for_subplan(const char *name, List *tlist,
 		attrs = lappend(attrs, makeString(pstrdup(buf)));
 	}
 
-	rte->rtekind = RTE_SPECIAL; /* XXX */
+	/*
+	 * We create an RTE_SPECIAL RangeTblEntry, and store the given tlist
+	 * in its coldeflist field.  This is a hack to make the tlist available
+	 * to get_name_for_var_field().  RTE_SPECIAL nodes shouldn't appear in
+	 * deparse contexts otherwise.
+	 */
+	rte->rtekind = RTE_SPECIAL;
 	rte->relid = InvalidOid;
+	rte->coldeflist = tlist;
 	rte->eref = makeAlias(name, attrs);
 	rte->inh = false;
 	rte->inFromCl = true;
@@ -2571,7 +2578,8 @@ get_names_for_var(Var *var, int levelsup, deparse_context *context,
  * Note: this has essentially the same logic as the parser's
  * expandRecordVariable() function, but we are dealing with a different
  * representation of the input context, and we only need one field name not
- * a TupleDesc.
+ * a TupleDesc.  Also, we have a special case for RTE_SPECIAL so that we can
+ * deal with displaying RECORD-returning functions in subplan targetlists.
  */
 static const char *
 get_name_for_var_field(Var *var, int fieldno,
@@ -2602,7 +2610,6 @@ get_name_for_var_field(Var *var, int fieldno,
 	switch (rte->rtekind)
 	{
 		case RTE_RELATION:
-		case RTE_SPECIAL:
 
 			/*
 			 * This case should not occur: a column of a table shouldn't have
@@ -2663,6 +2670,21 @@ get_name_for_var_field(Var *var, int fieldno,
 			 * its result columns as RECORD, which is not allowed.
 			 */
 			break;
+		case RTE_SPECIAL:
+			/*
+			 * This case occurs during EXPLAIN when we are looking at a
+			 * deparse context node set up by deparse_context_for_subplan().
+			 * Look into the subplan's target list to get the referenced
+			 * expression, and then pass it to get_expr_result_type().
+			 */
+			if (rte->coldeflist)
+			{
+				TargetEntry *ste = get_tle_by_resno(rte->coldeflist, attnum);
+
+				if (ste != NULL)
+					expr = (Node *) ste->expr;
+			}
+			break;
 	}
 
 	/*
-- 
GitLab