explain.c 25.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * explain.c
4
 *	  Explain query execution plans
5
 *
P
 
PostgreSQL Daemon 已提交
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994-5, Regents of the University of California
8
 *
9
 * IDENTIFICATION
P
 
PostgreSQL Daemon 已提交
10
 *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.129 2004/12/31 21:59:41 pgsql Exp $
11
 *
12
 *-------------------------------------------------------------------------
13
 */
14
#include "postgres.h"
M
Marc G. Fournier 已提交
15

16
#include "access/genam.h"
17 18
#include "access/heapam.h"
#include "catalog/pg_type.h"
19
#include "commands/explain.h"
20
#include "commands/prepare.h"
21
#include "commands/trigger.h"
22
#include "executor/executor.h"
23
#include "executor/instrument.h"
B
Bruce Momjian 已提交
24 25
#include "lib/stringinfo.h"
#include "nodes/print.h"
26
#include "optimizer/clauses.h"
27
#include "optimizer/planner.h"
28
#include "optimizer/var.h"
B
Bruce Momjian 已提交
29
#include "parser/parsetree.h"
30
#include "rewrite/rewriteHandler.h"
31
#include "tcop/pquery.h"
32
#include "utils/builtins.h"
33
#include "utils/guc.h"
34
#include "utils/lsyscache.h"
35

36

37 38 39
typedef struct ExplainState
{
	/* options */
40
	bool		printCost;		/* print cost */
41 42
	bool		printNodes;		/* do nodeToString() too */
	bool		printAnalyze;	/* print actual times */
43
	/* other states */
44
	List	   *rtable;			/* range table */
45
} ExplainState;
46

47
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
B
Bruce Momjian 已提交
48
				TupOutputState *tstate);
B
Bruce Momjian 已提交
49
static double elapsed_time(struct timeval * starttime);
50
static void explain_outNode(StringInfo str,
51
				Plan *plan, PlanState *planstate,
B
Bruce Momjian 已提交
52 53
				Plan *outer_plan,
				int indent, ExplainState *es);
54
static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
B
Bruce Momjian 已提交
55 56
			   int scanrelid, Plan *outer_plan,
			   StringInfo str, int indent, ExplainState *es);
57
static void show_upper_qual(List *qual, const char *qlabel,
B
Bruce Momjian 已提交
58 59 60
				const char *outer_name, int outer_varno, Plan *outer_plan,
				const char *inner_name, int inner_varno, Plan *inner_plan,
				StringInfo str, int indent, ExplainState *es);
61
static void show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
B
Bruce Momjian 已提交
62 63
			   const char *qlabel,
			   StringInfo str, int indent, ExplainState *es);
64
static Node *make_ors_ands_explicit(List *orclauses);
65 66 67

/*
 * ExplainQuery -
68
 *	  execute an EXPLAIN command
69 70
 */
void
71
ExplainQuery(ExplainStmt *stmt, DestReceiver *dest)
72
{
73
	Query	   *query = stmt->query;
74
	TupOutputState *tstate;
B
Bruce Momjian 已提交
75
	List	   *rewritten;
76
	ListCell   *l;
77

78 79 80 81 82 83 84 85 86 87
	/*
	 * Because the planner is not cool about not scribbling on its input,
	 * we make a preliminary copy of the source querytree.  This prevents
	 * problems in the case that the EXPLAIN is in a portal or plpgsql
	 * function and is executed repeatedly.  (See also the same hack in
	 * DECLARE CURSOR and PREPARE.)  XXX the planner really shouldn't
	 * modify its input ... FIXME someday.
	 */
	query = copyObject(query);

88
	/* prepare for projection of tuples */
89
	tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
90

91 92
	if (query->commandType == CMD_UTILITY)
	{
93
		/* Rewriter will not cope with utility statements */
94 95 96
		if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt))
			ExplainOneQuery(query, stmt, tstate);
		else if (query->utilityStmt && IsA(query->utilityStmt, ExecuteStmt))
97 98 99
			ExplainExecuteQuery(stmt, tstate);
		else
			do_text_output_oneline(tstate, "Utility statements have no plan structure");
100
	}
101
	else
B
Bruce Momjian 已提交
102
	{
103 104 105 106 107 108
		/* Rewrite through rule system */
		rewritten = QueryRewrite(query);

		if (rewritten == NIL)
		{
			/* In the case of an INSTEAD NOTHING, tell at least that */
109
			do_text_output_oneline(tstate, "Query rewrites to nothing");
110 111 112 113 114 115 116 117
		}
		else
		{
			/* Explain every plan */
			foreach(l, rewritten)
			{
				ExplainOneQuery(lfirst(l), stmt, tstate);
				/* put a blank line between plans */
118
				if (lnext(l) != NULL)
119
					do_text_output_oneline(tstate, "");
120 121
			}
		}
B
Bruce Momjian 已提交
122 123
	}

124
	end_tup_output(tstate);
B
Bruce Momjian 已提交
125 126
}

127 128 129 130 131 132 133 134 135 136 137 138
/*
 * ExplainResultDesc -
 *	  construct the result tupledesc for an EXPLAIN
 */
TupleDesc
ExplainResultDesc(ExplainStmt *stmt)
{
	TupleDesc	tupdesc;

	/* need a tuple descriptor representing a single TEXT column */
	tupdesc = CreateTemplateTupleDesc(1, false);
	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
139
					   TEXTOID, -1, 0);
140 141 142
	return tupdesc;
}

B
Bruce Momjian 已提交
143 144 145 146 147
/*
 * ExplainOneQuery -
 *	  print out the execution plan for one query
 */
static void
148
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
B
Bruce Momjian 已提交
149 150
{
	Plan	   *plan;
151
	QueryDesc  *queryDesc;
152 153
	bool		isCursor = false;
	int			cursorOptions = 0;
B
Bruce Momjian 已提交
154

155 156 157
	/* planner will not cope with utility statements */
	if (query->commandType == CMD_UTILITY)
	{
158 159 160 161 162 163 164 165 166 167 168 169
		if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt))
		{
			DeclareCursorStmt *dcstmt;
			List	   *rewritten;

			dcstmt = (DeclareCursorStmt *) query->utilityStmt;
			query = (Query *) dcstmt->query;
			isCursor = true;
			cursorOptions = dcstmt->options;
			/* Still need to rewrite cursor command */
			Assert(query->commandType == CMD_SELECT);
			rewritten = QueryRewrite(query);
170
			if (list_length(rewritten) != 1)
171
				elog(ERROR, "unexpected rewrite result");
172
			query = (Query *) linitial(rewritten);
173 174 175 176 177 178
			Assert(query->commandType == CMD_SELECT);
			/* do not actually execute the underlying query! */
			stmt->analyze = false;
		}
		else if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
		{
179
			do_text_output_oneline(tstate, "NOTIFY");
180 181
			return;
		}
182
		else
183
		{
184
			do_text_output_oneline(tstate, "UTILITY");
185 186
			return;
		}
187 188
	}

189
	/* plan the query */
190
	plan = planner(query, isCursor, cursorOptions, NULL);
B
Bruce Momjian 已提交
191

192
	/* Create a QueryDesc requesting no output */
193 194 195
	queryDesc = CreateQueryDesc(query, plan,
								ActiveSnapshot, InvalidSnapshot,
								None_Receiver, NULL,
196 197
								stmt->analyze);

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
	ExplainOnePlan(queryDesc, stmt, tstate);
}

/*
 * ExplainOnePlan -
 *		given a planned query, execute it if needed, and then print
 *		EXPLAIN output
 *
 * This is exported because it's called back from prepare.c in the
 * EXPLAIN EXECUTE case
 *
 * Note: the passed-in QueryDesc is freed when we're done with it
 */
void
ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
			   TupOutputState *tstate)
{
	struct timeval starttime;
	double		totaltime = 0;
	ExplainState *es;
	StringInfo	str;

	gettimeofday(&starttime, NULL);

222 223 224 225
	/* If analyzing, we need to cope with queued triggers */
	if (stmt->analyze)
		AfterTriggerBeginQuery();

226
	/* call ExecutorStart to prepare the plan for execution */
227
	ExecutorStart(queryDesc, !stmt->analyze);
228

229
	/* Execute the plan for statistics if asked for */
230
	if (stmt->analyze)
231
	{
232 233
		/* run the plan */
		ExecutorRun(queryDesc, ForwardScanDirection, 0L);
234

235 236
		/* We can't clean up 'till we're done printing the stats... */
		totaltime += elapsed_time(&starttime);
237 238
	}

239
	es = (ExplainState *) palloc0(sizeof(ExplainState));
B
Bruce Momjian 已提交
240

241
	es->printCost = true;		/* default */
242 243
	es->printNodes = stmt->verbose;
	es->printAnalyze = stmt->analyze;
244
	es->rtable = queryDesc->parsetree->rtable;
245 246

	if (es->printNodes)
247
	{
248
		char	   *s;
249
		char	   *f;
250

251
		s = nodeToString(queryDesc->plantree);
252 253
		if (s)
		{
254 255 256 257
			if (Explain_pretty_print)
				f = pretty_format_node_dump(s);
			else
				f = format_node_dump(s);
258
			pfree(s);
259 260 261
			do_text_output_multiline(tstate, f);
			pfree(f);
			if (es->printCost)
B
Bruce Momjian 已提交
262
				do_text_output_oneline(tstate, "");		/* separator line */
263 264
		}
	}
265

266 267
	str = makeStringInfo();

268 269
	if (es->printCost)
	{
270
		explain_outNode(str, queryDesc->plantree, queryDesc->planstate,
271 272 273 274
						NULL, 0, es);
	}

	/*
275 276
	 * Close down the query and free resources; also run any queued
	 * AFTER triggers.  Include time for this in the total runtime.
277 278
	 */
	gettimeofday(&starttime, NULL);
279

280
	ExecutorEnd(queryDesc);
281 282 283 284

	if (stmt->analyze)
		AfterTriggerEndQuery();

285 286
	FreeQueryDesc(queryDesc);

287 288 289
	/* We need a CCI just in case query expanded to multiple plans */
	if (stmt->analyze)
		CommandCounterIncrement();
290 291 292 293 294

	totaltime += elapsed_time(&starttime);

	if (es->printCost)
	{
295
		if (stmt->analyze)
296
			appendStringInfo(str, "Total runtime: %.3f ms\n",
297
							 1000.0 * totaltime);
298
		do_text_output_multiline(tstate, str->data);
B
Bruce Momjian 已提交
299
	}
300

301 302
	pfree(str->data);
	pfree(str);
B
Bruce Momjian 已提交
303
	pfree(es);
304 305
}

306 307
/* Compute elapsed time in seconds since given gettimeofday() timestamp */
static double
B
Bruce Momjian 已提交
308
elapsed_time(struct timeval * starttime)
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
{
	struct timeval endtime;

	gettimeofday(&endtime, NULL);

	endtime.tv_sec -= starttime->tv_sec;
	endtime.tv_usec -= starttime->tv_usec;
	while (endtime.tv_usec < 0)
	{
		endtime.tv_usec += 1000000;
		endtime.tv_sec--;
	}
	return (double) endtime.tv_sec +
		(double) endtime.tv_usec / 1000000.0;
}
324 325 326

/*
 * explain_outNode -
327 328
 *	  converts a Plan node into ascii string and appends it to 'str'
 *
329 330 331 332
 * planstate points to the executor state node corresponding to the plan node.
 * We need this to get at the instrumentation data (if any) as well as the
 * list of subplans.
 *
333 334 335
 * outer_plan, if not null, references another plan node that is the outer
 * side of a join with the current node.  This is only interesting for
 * deciphering runtime keys of an inner indexscan.
336 337
 */
static void
338
explain_outNode(StringInfo str,
339
				Plan *plan, PlanState *planstate,
340
				Plan *outer_plan,
341
				int indent, ExplainState *es)
342
{
B
Bruce Momjian 已提交
343
	ListCell   *l;
B
Bruce Momjian 已提交
344 345
	char	   *pname;
	int			i;
346 347 348

	if (plan == NULL)
	{
349
		appendStringInfoChar(str, '\n');
350 351 352 353 354
		return;
	}

	switch (nodeTag(plan))
	{
355 356 357 358 359 360 361
		case T_Result:
			pname = "Result";
			break;
		case T_Append:
			pname = "Append";
			break;
		case T_NestLoop:
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
			switch (((NestLoop *) plan)->join.jointype)
			{
				case JOIN_INNER:
					pname = "Nested Loop";
					break;
				case JOIN_LEFT:
					pname = "Nested Loop Left Join";
					break;
				case JOIN_FULL:
					pname = "Nested Loop Full Join";
					break;
				case JOIN_RIGHT:
					pname = "Nested Loop Right Join";
					break;
				case JOIN_IN:
					pname = "Nested Loop IN Join";
					break;
				default:
					pname = "Nested Loop ??? Join";
					break;
			}
383 384
			break;
		case T_MergeJoin:
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
			switch (((MergeJoin *) plan)->join.jointype)
			{
				case JOIN_INNER:
					pname = "Merge Join";
					break;
				case JOIN_LEFT:
					pname = "Merge Left Join";
					break;
				case JOIN_FULL:
					pname = "Merge Full Join";
					break;
				case JOIN_RIGHT:
					pname = "Merge Right Join";
					break;
				case JOIN_IN:
					pname = "Merge IN Join";
					break;
				default:
					pname = "Merge ??? Join";
					break;
			}
406 407
			break;
		case T_HashJoin:
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
			switch (((HashJoin *) plan)->join.jointype)
			{
				case JOIN_INNER:
					pname = "Hash Join";
					break;
				case JOIN_LEFT:
					pname = "Hash Left Join";
					break;
				case JOIN_FULL:
					pname = "Hash Full Join";
					break;
				case JOIN_RIGHT:
					pname = "Hash Right Join";
					break;
				case JOIN_IN:
					pname = "Hash IN Join";
					break;
				default:
					pname = "Hash ??? Join";
					break;
			}
429 430 431 432 433 434 435
			break;
		case T_SeqScan:
			pname = "Seq Scan";
			break;
		case T_IndexScan:
			pname = "Index Scan";
			break;
436 437 438 439 440 441
		case T_TidScan:
			pname = "Tid Scan";
			break;
		case T_SubqueryScan:
			pname = "Subquery Scan";
			break;
442 443 444
		case T_FunctionScan:
			pname = "Function Scan";
			break;
445 446 447
		case T_Material:
			pname = "Materialize";
			break;
448 449 450 451 452 453 454
		case T_Sort:
			pname = "Sort";
			break;
		case T_Group:
			pname = "Group";
			break;
		case T_Agg:
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
			switch (((Agg *) plan)->aggstrategy)
			{
				case AGG_PLAIN:
					pname = "Aggregate";
					break;
				case AGG_SORTED:
					pname = "GroupAggregate";
					break;
				case AGG_HASHED:
					pname = "HashAggregate";
					break;
				default:
					pname = "Aggregate ???";
					break;
			}
470 471 472 473
			break;
		case T_Unique:
			pname = "Unique";
			break;
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
		case T_SetOp:
			switch (((SetOp *) plan)->cmd)
			{
				case SETOPCMD_INTERSECT:
					pname = "SetOp Intersect";
					break;
				case SETOPCMD_INTERSECT_ALL:
					pname = "SetOp Intersect All";
					break;
				case SETOPCMD_EXCEPT:
					pname = "SetOp Except";
					break;
				case SETOPCMD_EXCEPT_ALL:
					pname = "SetOp Except All";
					break;
				default:
					pname = "SetOp ???";
					break;
			}
			break;
494 495 496
		case T_Limit:
			pname = "Limit";
			break;
497 498 499 500
		case T_Hash:
			pname = "Hash";
			break;
		default:
501
			pname = "???";
502
			break;
503 504
	}

505
	appendStringInfoString(str, pname);
506 507
	switch (nodeTag(plan))
	{
508
		case T_IndexScan:
509
			if (ScanDirectionIsBackward(((IndexScan *) plan)->indxorderdir))
510 511
				appendStringInfoString(str, " Backward");
			appendStringInfoString(str, " using ");
V
Vadim B. Mikheev 已提交
512
			i = 0;
B
Bruce Momjian 已提交
513
			foreach(l, ((IndexScan *) plan)->indxid)
V
Vadim B. Mikheev 已提交
514
			{
515
				char	   *indname;
516

517
				indname = get_rel_name(lfirst_oid(l));
518 519
				appendStringInfo(str, "%s%s",
								 (++i > 1) ? ", " : "",
520
								 quote_identifier(indname));
V
Vadim B. Mikheev 已提交
521
			}
522
			/* FALL THRU */
523
		case T_SeqScan:
524
		case T_TidScan:
525 526
			if (((Scan *) plan)->scanrelid > 0)
			{
527 528
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
529
				char	   *relname;
530 531

				/* Assume it's on a real relation */
532
				Assert(rte->rtekind == RTE_RELATION);
533 534 535

				/* We only show the rel name, not schema name */
				relname = get_rel_name(rte->relid);
536

537
				appendStringInfo(str, " on %s",
538
								 quote_identifier(relname));
539
				if (strcmp(rte->eref->aliasname, relname) != 0)
540
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
541
								 quote_identifier(rte->eref->aliasname));
542 543 544 545 546 547 548 549 550
			}
			break;
		case T_SubqueryScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);

				appendStringInfo(str, " %s",
551
								 quote_identifier(rte->eref->aliasname));
552 553
			}
			break;
554 555 556 557 558
		case T_FunctionScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
559
				char	   *proname;
560 561 562 563

				/* Assert it's on a RangeFunction */
				Assert(rte->rtekind == RTE_FUNCTION);

564 565 566
				/*
				 * If the expression is still a function call, we can get
				 * the real name of the function.  Otherwise, punt (this
B
Bruce Momjian 已提交
567 568
				 * can happen if the optimizer simplified away the
				 * function call, for example).
569 570 571 572 573 574 575 576 577 578 579
				 */
				if (rte->funcexpr && IsA(rte->funcexpr, FuncExpr))
				{
					FuncExpr   *funcexpr = (FuncExpr *) rte->funcexpr;
					Oid			funcid = funcexpr->funcid;

					/* We only show the func name, not schema name */
					proname = get_func_name(funcid);
				}
				else
					proname = rte->eref->aliasname;
580 581 582 583 584

				appendStringInfo(str, " on %s",
								 quote_identifier(proname));
				if (strcmp(rte->eref->aliasname, proname) != 0)
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
585
								 quote_identifier(rte->eref->aliasname));
586 587
			}
			break;
588 589
		default:
			break;
590 591 592
	}
	if (es->printCost)
	{
593 594 595
		appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
						 plan->startup_cost, plan->total_cost,
						 plan->plan_rows, plan->plan_width);
596

597 598 599 600 601 602 603
		/*
		 * We have to forcibly clean up the instrumentation state because
		 * we haven't done ExecutorEnd yet.  This is pretty grotty ...
		 */
		InstrEndLoop(planstate->instrument);

		if (planstate->instrument && planstate->instrument->nloops > 0)
604
		{
605
			double		nloops = planstate->instrument->nloops;
606

607
			appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
B
Bruce Momjian 已提交
608 609
						1000.0 * planstate->instrument->startup / nloops,
						  1000.0 * planstate->instrument->total / nloops,
610 611
							 planstate->instrument->ntuples / nloops,
							 planstate->instrument->nloops);
612
		}
613
		else if (es->printAnalyze)
614
			appendStringInfo(str, " (never executed)");
615
	}
616
	appendStringInfoChar(str, '\n');
617

618
	/* quals, sort keys, etc */
619 620 621 622
	switch (nodeTag(plan))
	{
		case T_IndexScan:
			show_scan_qual(((IndexScan *) plan)->indxqualorig, true,
623
						   "Index Cond",
624
						   ((Scan *) plan)->scanrelid,
625
						   outer_plan,
626
						   str, indent, es);
627 628
			show_scan_qual(plan->qual, false,
						   "Filter",
629
						   ((Scan *) plan)->scanrelid,
630
						   outer_plan,
631 632 633 634
						   str, indent, es);
			break;
		case T_SeqScan:
		case T_TidScan:
635
		case T_SubqueryScan:
636
		case T_FunctionScan:
637 638
			show_scan_qual(plan->qual, false,
						   "Filter",
639
						   ((Scan *) plan)->scanrelid,
640
						   outer_plan,
641 642 643
						   str, indent, es);
			break;
		case T_NestLoop:
644
			show_upper_qual(((NestLoop *) plan)->join.joinqual,
645
							"Join Filter",
646 647 648
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
649 650
			show_upper_qual(plan->qual,
							"Filter",
651 652 653 654 655
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_MergeJoin:
656 657
			show_upper_qual(((MergeJoin *) plan)->mergeclauses,
							"Merge Cond",
658 659 660
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
661
			show_upper_qual(((MergeJoin *) plan)->join.joinqual,
662
							"Join Filter",
663 664 665
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
666 667
			show_upper_qual(plan->qual,
							"Filter",
668 669 670 671 672
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_HashJoin:
673 674
			show_upper_qual(((HashJoin *) plan)->hashclauses,
							"Hash Cond",
675 676 677
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
678
			show_upper_qual(((HashJoin *) plan)->join.joinqual,
679
							"Join Filter",
680 681 682
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
683 684
			show_upper_qual(plan->qual,
							"Filter",
685 686 687 688 689 690
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_Agg:
		case T_Group:
691 692
			show_upper_qual(plan->qual,
							"Filter",
693 694 695 696
							"subplan", 0, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
697
		case T_Sort:
698 699 700
			show_sort_keys(plan->targetlist,
						   ((Sort *) plan)->numCols,
						   ((Sort *) plan)->sortColIdx,
701 702 703
						   "Sort Key",
						   str, indent, es);
			break;
704 705
		case T_Result:
			show_upper_qual((List *) ((Result *) plan)->resconstantqual,
706
							"One-Time Filter",
707 708 709
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
710 711
			show_upper_qual(plan->qual,
							"Filter",
712 713 714 715 716 717 718 719
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
		default:
			break;
	}

V
Vadim B. Mikheev 已提交
720 721 722
	/* initPlan-s */
	if (plan->initPlan)
	{
723
		List	   *saved_rtable = es->rtable;
724
		ListCell   *lst;
725

B
Bruce Momjian 已提交
726
		for (i = 0; i < indent; i++)
V
Vadim B. Mikheev 已提交
727 728
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  InitPlan\n");
729
		foreach(lst, planstate->initPlan)
V
Vadim B. Mikheev 已提交
730
		{
731
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
732
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
733

734
			es->rtable = sp->rtable;
V
Vadim B. Mikheev 已提交
735 736 737
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
738 739
			explain_outNode(str, sp->plan,
							sps->planstate,
740
							NULL,
741
							indent + 4, es);
V
Vadim B. Mikheev 已提交
742 743 744
		}
		es->rtable = saved_rtable;
	}
745 746 747 748 749 750

	/* lefttree */
	if (outerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
751
		appendStringInfo(str, "  ->  ");
752 753 754 755
		explain_outNode(str, outerPlan(plan),
						outerPlanState(planstate),
						NULL,
						indent + 3, es);
756
	}
757 758 759 760 761 762

	/* righttree */
	if (innerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
763
		appendStringInfo(str, "  ->  ");
764 765 766
		explain_outNode(str, innerPlan(plan),
						innerPlanState(planstate),
						outerPlan(plan),
767
						indent + 3, es);
V
Vadim B. Mikheev 已提交
768
	}
769

770
	if (IsA(plan, Append))
771
	{
772
		Append	   *appendplan = (Append *) plan;
773
		AppendState *appendstate = (AppendState *) planstate;
774
		ListCell   *lst;
775
		int			j;
776

777
		j = 0;
778 779
		foreach(lst, appendplan->appendplans)
		{
780
			Plan	   *subnode = (Plan *) lfirst(lst);
781 782 783

			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
784
			appendStringInfo(str, "  ->  ");
785

786 787 788 789 790
			explain_outNode(str, subnode,
							appendstate->appendplans[j],
							NULL,
							indent + 3, es);
			j++;
791 792
		}
	}
793 794 795 796

	if (IsA(plan, SubqueryScan))
	{
		SubqueryScan *subqueryscan = (SubqueryScan *) plan;
797
		SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
798 799 800 801 802
		Plan	   *subnode = subqueryscan->subplan;
		RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
									  es->rtable);
		List	   *saved_rtable = es->rtable;

803
		Assert(rte->rtekind == RTE_SUBQUERY);
804 805 806 807 808 809
		es->rtable = rte->subquery->rtable;

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  ->  ");

810 811 812 813
		explain_outNode(str, subnode,
						subquerystate->subplan,
						NULL,
						indent + 3, es);
814 815 816 817 818

		es->rtable = saved_rtable;
	}

	/* subPlan-s */
819
	if (planstate->subPlan)
820 821
	{
		List	   *saved_rtable = es->rtable;
822
		ListCell   *lst;
823 824 825 826

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  SubPlan\n");
827
		foreach(lst, planstate->subPlan)
828
		{
829
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
830
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
831 832

			es->rtable = sp->rtable;
833 834 835
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
836 837 838
			explain_outNode(str, sp->plan,
							sps->planstate,
							NULL,
839 840 841 842
							indent + 4, es);
		}
		es->rtable = saved_rtable;
	}
843 844
}

845 846 847 848 849
/*
 * Show a qualifier expression for a scan plan node
 */
static void
show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
850
			   int scanrelid, Plan *outer_plan,
851 852 853
			   StringInfo str, int indent, ExplainState *es)
{
	RangeTblEntry *rte;
854 855
	Node	   *scancontext;
	Node	   *outercontext;
856 857 858 859 860 861 862 863
	List	   *context;
	Node	   *node;
	char	   *exprstr;
	int			i;

	/* No work if empty qual */
	if (qual == NIL)
		return;
864 865
	if (is_or_qual && list_length(qual) == 1 && linitial(qual) == NIL)
		return;
866

867 868 869 870 871 872
	/* Fix qual --- indexqual requires different processing */
	if (is_or_qual)
		node = make_ors_ands_explicit(qual);
	else
		node = (Node *) make_ands_explicit(qual);

873
	/* Generate deparse context */
874
	Assert(scanrelid > 0 && scanrelid <= list_length(es->rtable));
875
	rte = rt_fetch(scanrelid, es->rtable);
876
	scancontext = deparse_context_for_rte(rte);
877 878 879

	/*
	 * If we have an outer plan that is referenced by the qual, add it to
B
Bruce Momjian 已提交
880 881
	 * the deparse context.  If not, don't (so that we don't force
	 * prefixes unnecessarily).
882 883 884
	 */
	if (outer_plan)
	{
B
Bruce Momjian 已提交
885
		Relids		varnos = pull_varnos(node);
886 887

		if (bms_is_member(OUTER, varnos))
888
			outercontext = deparse_context_for_subplan("outer",
B
Bruce Momjian 已提交
889
												  outer_plan->targetlist,
890 891 892
													   es->rtable);
		else
			outercontext = NULL;
893
		bms_free(varnos);
894
	}
895
	else
896 897 898
		outercontext = NULL;

	context = deparse_context_for_plan(scanrelid, scancontext,
899 900
									   OUTER, outercontext,
									   NIL);
901 902

	/* Deparse the expression */
903
	exprstr = deparse_expression(node, context, (outercontext != NULL), false);
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944

	/* And add to str */
	for (i = 0; i < indent; i++)
		appendStringInfo(str, "  ");
	appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
}

/*
 * Show a qualifier expression for an upper-level plan node
 */
static void
show_upper_qual(List *qual, const char *qlabel,
				const char *outer_name, int outer_varno, Plan *outer_plan,
				const char *inner_name, int inner_varno, Plan *inner_plan,
				StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
	Node	   *outercontext;
	Node	   *innercontext;
	Node	   *node;
	char	   *exprstr;
	int			i;

	/* No work if empty qual */
	if (qual == NIL)
		return;

	/* Generate deparse context */
	if (outer_plan)
		outercontext = deparse_context_for_subplan(outer_name,
												   outer_plan->targetlist,
												   es->rtable);
	else
		outercontext = NULL;
	if (inner_plan)
		innercontext = deparse_context_for_subplan(inner_name,
												   inner_plan->targetlist,
												   es->rtable);
	else
		innercontext = NULL;
	context = deparse_context_for_plan(outer_varno, outercontext,
945 946
									   inner_varno, innercontext,
									   NIL);
947 948 949

	/* Deparse the expression */
	node = (Node *) make_ands_explicit(qual);
950
	exprstr = deparse_expression(node, context, (inner_plan != NULL), false);
951 952 953 954 955 956 957

	/* And add to str */
	for (i = 0; i < indent; i++)
		appendStringInfo(str, "  ");
	appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
}

958 959 960 961
/*
 * Show the sort keys for a Sort node.
 */
static void
962 963
show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
			   const char *qlabel,
964 965 966 967 968 969
			   StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
	bool		useprefix;
	int			keyno;
	char	   *exprstr;
970
	Relids		varnos;
971 972 973 974 975 976 977 978 979 980 981
	int			i;

	if (nkeys <= 0)
		return;

	for (i = 0; i < indent; i++)
		appendStringInfo(str, "  ");
	appendStringInfo(str, "  %s: ", qlabel);

	/*
	 * In this routine we expect that the plan node's tlist has not been
B
Bruce Momjian 已提交
982 983 984 985 986
	 * processed by set_plan_references().	Normally, any Vars will
	 * contain valid varnos referencing the actual rtable.	But we might
	 * instead be looking at a dummy tlist generated by prepunion.c; if
	 * there are Vars with zero varno, use the tlist itself to determine
	 * their names.
987
	 */
988 989
	varnos = pull_varnos((Node *) tlist);
	if (bms_is_member(0, varnos))
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
	{
		Node	   *outercontext;

		outercontext = deparse_context_for_subplan("sort",
												   tlist,
												   es->rtable);
		context = deparse_context_for_plan(0, outercontext,
										   0, NULL,
										   NIL);
		useprefix = false;
	}
	else
	{
		context = deparse_context_for_plan(0, NULL,
										   0, NULL,
										   es->rtable);
1006
		useprefix = list_length(es->rtable) > 1;
1007
	}
1008
	bms_free(varnos);
1009

1010
	for (keyno = 0; keyno < nkeys; keyno++)
1011 1012
	{
		/* find key expression in tlist */
1013
		AttrNumber	keyresno = keycols[keyno];
1014
		TargetEntry *target = get_tle_by_resno(tlist, keyresno);
1015

1016
		if (!target)
1017
			elog(ERROR, "no tlist entry for key %d", keyresno);
1018 1019 1020 1021 1022 1023
		/* Deparse the expression, showing any top-level cast */
		exprstr = deparse_expression((Node *) target->expr, context,
									 useprefix, true);
		/* And add to str */
		if (keyno > 0)
			appendStringInfo(str, ", ");
N
Neil Conway 已提交
1024
		appendStringInfoString(str, exprstr);
1025 1026 1027 1028 1029
	}

	appendStringInfo(str, "\n");
}

1030
/*
B
Bruce Momjian 已提交
1031
 * Indexscan qual lists have an implicit OR-of-ANDs structure.	Make it
1032 1033 1034 1035 1036 1037 1038
 * explicit so deparsing works properly.
 */
static Node *
make_ors_ands_explicit(List *orclauses)
{
	if (orclauses == NIL)
		return NULL;			/* probably can't happen */
1039 1040
	else if (list_length(orclauses) == 1)
		return (Node *) make_ands_explicit(linitial(orclauses));
1041 1042
	else
	{
1043 1044
		List	   *args = NIL;
		ListCell   *orptr;
1045 1046

		foreach(orptr, orclauses)
1047
			args = lappend(args, make_ands_explicit(lfirst(orptr)));
1048

1049
		return (Node *) make_orclause(args);
1050 1051
	}
}