As I was trying to figure out the least invasive way to make
explain_outNode() support machine-readable output, I noticed that
there is a whole pile of duplicated code for dealing with scan
targets.  The attached refactoring may be worth applying independently
of what happens with the rest of the project, so it's attached here
for review and comment.

This also removes a redundant branch of a switch further down, folding
T_SubqueryScan into the preceding chunk.

It's tempting to simplify this further by ripping some of the asserts
out of ExplainScanTarget() on the theory that, while it may be good
sanity checking, it's not really EXPLAIN's job to do this type of
validation.  But I've left them alone for now.

...Robert
*** a/src/backend/commands/explain.c
--- b/src/backend/commands/explain.c
***************
*** 73,78 **** static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
--- 73,79 ----
  static void show_sort_info(SortState *sortstate,
  			   StringInfo str, int indent, ExplainState *es);
  static const char *explain_get_index_name(Oid indexId);
+ static void ExplainScanTarget(StringInfo str, Scan *plan, ExplainState *es);
  
  
  /*
***************
*** 668,790 **** explain_outNode(StringInfo str,
  		case T_SeqScan:
  		case T_BitmapHeapScan:
  		case T_TidScan:
- 			if (((Scan *) plan)->scanrelid > 0)
- 			{
- 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
- 											  es->rtable);
- 				char	   *relname;
- 
- 				/* Assume it's on a real relation */
- 				Assert(rte->rtekind == RTE_RELATION);
- 
- 				/* We only show the rel name, not schema name */
- 				relname = get_rel_name(rte->relid);
- 
- 				appendStringInfo(str, " on %s",
- 								 quote_identifier(relname));
- 				if (strcmp(rte->eref->aliasname, relname) != 0)
- 					appendStringInfo(str, " %s",
- 									 quote_identifier(rte->eref->aliasname));
- 			}
- 			break;
- 		case T_BitmapIndexScan:
- 			appendStringInfo(str, " on %s",
- 				explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
- 			break;
  		case T_SubqueryScan:
- 			if (((Scan *) plan)->scanrelid > 0)
- 			{
- 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
- 											  es->rtable);
- 
- 				appendStringInfo(str, " %s",
- 								 quote_identifier(rte->eref->aliasname));
- 			}
- 			break;
  		case T_FunctionScan:
- 			if (((Scan *) plan)->scanrelid > 0)
- 			{
- 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
- 											  es->rtable);
- 				Node	   *funcexpr;
- 				char	   *proname;
- 
- 				/* Assert it's on a RangeFunction */
- 				Assert(rte->rtekind == RTE_FUNCTION);
- 
- 				/*
- 				 * If the expression is still a function call, we can get the
- 				 * real name of the function.  Otherwise, punt (this can
- 				 * happen if the optimizer simplified away the function call,
- 				 * for example).
- 				 */
- 				funcexpr = ((FunctionScan *) plan)->funcexpr;
- 				if (funcexpr && IsA(funcexpr, FuncExpr))
- 				{
- 					Oid			funcid = ((FuncExpr *) funcexpr)->funcid;
- 
- 					/* We only show the func name, not schema name */
- 					proname = get_func_name(funcid);
- 				}
- 				else
- 					proname = rte->eref->aliasname;
- 
- 				appendStringInfo(str, " on %s",
- 								 quote_identifier(proname));
- 				if (strcmp(rte->eref->aliasname, proname) != 0)
- 					appendStringInfo(str, " %s",
- 									 quote_identifier(rte->eref->aliasname));
- 			}
- 			break;
  		case T_ValuesScan:
- 			if (((Scan *) plan)->scanrelid > 0)
- 			{
- 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
- 											  es->rtable);
- 				char	   *valsname;
- 
- 				/* Assert it's on a values rte */
- 				Assert(rte->rtekind == RTE_VALUES);
- 
- 				valsname = rte->eref->aliasname;
- 
- 				appendStringInfo(str, " on %s",
- 								 quote_identifier(valsname));
- 			}
- 			break;
  		case T_CteScan:
- 			if (((Scan *) plan)->scanrelid > 0)
- 			{
- 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
- 											  es->rtable);
- 
- 				/* Assert it's on a non-self-reference CTE */
- 				Assert(rte->rtekind == RTE_CTE);
- 				Assert(!rte->self_reference);
- 
- 				appendStringInfo(str, " on %s",
- 								 quote_identifier(rte->ctename));
- 				if (strcmp(rte->eref->aliasname, rte->ctename) != 0)
- 					appendStringInfo(str, " %s",
- 									 quote_identifier(rte->eref->aliasname));
- 			}
- 			break;
  		case T_WorkTableScan:
! 			if (((Scan *) plan)->scanrelid > 0)
! 			{
! 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
! 											  es->rtable);
! 
! 				/* Assert it's on a self-reference CTE */
! 				Assert(rte->rtekind == RTE_CTE);
! 				Assert(rte->self_reference);
! 
! 				appendStringInfo(str, " on %s",
! 								 quote_identifier(rte->ctename));
! 				if (strcmp(rte->eref->aliasname, rte->ctename) != 0)
! 					appendStringInfo(str, " %s",
! 									 quote_identifier(rte->eref->aliasname));
! 			}
  			break;
  		default:
  			break;
--- 669,684 ----
  		case T_SeqScan:
  		case T_BitmapHeapScan:
  		case T_TidScan:
  		case T_SubqueryScan:
  		case T_FunctionScan:
  		case T_ValuesScan:
  		case T_CteScan:
  		case T_WorkTableScan:
! 			ExplainScanTarget(str, (Scan *) plan, es);
! 			break;
! 		case T_BitmapIndexScan:
! 			appendStringInfo(str, " on %s",
! 				explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
  			break;
  		default:
  			break;
***************
*** 854,865 **** explain_outNode(StringInfo str,
  		case T_ValuesScan:
  		case T_CteScan:
  		case T_WorkTableScan:
- 			show_scan_qual(plan->qual,
- 						   "Filter",
- 						   ((Scan *) plan)->scanrelid,
- 						   plan, outer_plan,
- 						   str, indent, es);
- 			break;
  		case T_SubqueryScan:
  			show_scan_qual(plan->qual,
  						   "Filter",
--- 748,753 ----
***************
*** 1340,1342 **** explain_get_index_name(Oid indexId)
--- 1228,1297 ----
  	}
  	return result;
  }
+ 
+ /*
+  * Explain details for Scan nodes.
+  */
+ static void
+ ExplainScanTarget(StringInfo str, Scan *plan, ExplainState *es)
+ {
+ 	char *objectname = NULL;
+ 	Node *funcexpr;
+ 	RangeTblEntry *rte;
+ 
+ 	if (plan->scanrelid <= 0)
+ 		return;
+ 	rte = rt_fetch(plan->scanrelid, es->rtable);
+ 
+ 	switch (nodeTag(plan))
+ 	{
+ 		case T_IndexScan:
+ 		case T_SeqScan:
+ 		case T_BitmapHeapScan:
+ 		case T_TidScan:
+ 			/* Assert it's on a real relation */
+ 			Assert(rte->rtekind == RTE_RELATION);
+ 			objectname = get_rel_name(rte->relid);
+ 			break;
+ 		case T_FunctionScan:
+ 			/* Assert it's on a RangeFunction */
+ 			Assert(rte->rtekind == RTE_FUNCTION);
+ 
+ 			/*
+ 			 * If the expression is still a function call, we can get the
+ 			 * real name of the function.  Otherwise, punt (this can
+ 			 * happen if the optimizer simplified away the function call,
+ 			 * for example).
+ 			 */
+ 			funcexpr = ((FunctionScan *) plan)->funcexpr;
+ 			if (funcexpr && IsA(funcexpr, FuncExpr))
+ 			{
+ 				Oid			funcid = ((FuncExpr *) funcexpr)->funcid;
+ 				objectname = get_func_name(funcid);
+ 			}
+ 			break;
+ 		case T_ValuesScan:
+ 			Assert(rte->rtekind == RTE_VALUES);
+ 			break;
+ 		case T_CteScan:
+ 			/* Assert it's on a non-self-reference CTE */
+ 			Assert(rte->rtekind == RTE_CTE);
+ 			Assert(!rte->self_reference);
+ 			objectname = rte->ctename;
+ 			break;
+ 		case T_WorkTableScan:
+ 			/* Assert it's on a self-reference CTE */
+ 			Assert(rte->rtekind == RTE_CTE);
+ 			Assert(rte->self_reference);
+ 			objectname = rte->ctename;
+ 			break;
+ 		default:
+ 			break;
+ 	}
+ 
+ 	appendStringInfoString(str, " on");
+ 	if (objectname != NULL)
+ 		appendStringInfo(str, " %s", quote_identifier(objectname));
+ 	if (objectname == NULL || strcmp(rte->eref->aliasname, objectname) != 0)
+ 		appendStringInfo(str, " %s", quote_identifier(rte->eref->aliasname));
+ }
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to