explain.c 28.8 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
10
 *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.136 2005/06/03 23:05:28 tgl Exp $
11
 *
12
 *-------------------------------------------------------------------------
13
 */
14
#include "postgres.h"
M
Marc G. Fournier 已提交
15

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

37

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

48
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
B
Bruce Momjian 已提交
49
				TupOutputState *tstate);
50
static double elapsed_time(instr_time *starttime);
51
static void explain_outNode(StringInfo str,
52
				Plan *plan, PlanState *planstate,
B
Bruce Momjian 已提交
53 54
				Plan *outer_plan,
				int indent, ExplainState *es);
55
static void show_scan_qual(List *qual, const char *qlabel,
B
Bruce Momjian 已提交
56 57
			   int scanrelid, Plan *outer_plan,
			   StringInfo str, int indent, ExplainState *es);
58
static void show_upper_qual(List *qual, const char *qlabel,
B
Bruce Momjian 已提交
59 60 61
				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);
62
static void show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
B
Bruce Momjian 已提交
63 64
			   const char *qlabel,
			   StringInfo str, int indent, ExplainState *es);
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
		/*
		 * Must acquire locks in case we didn't come fresh from the parser.
		 * XXX this also scribbles on query, another reason for copyObject
		 */
		AcquireRewriteLocks(query);

109 110 111 112 113 114
		/* Rewrite through rule system */
		rewritten = QueryRewrite(query);

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

130
	end_tup_output(tstate);
B
Bruce Momjian 已提交
131 132
}

133 134 135 136 137 138 139 140 141 142 143 144
/*
 * 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",
145
					   TEXTOID, -1, 0);
146 147 148
	return tupdesc;
}

B
Bruce Momjian 已提交
149 150 151 152 153
/*
 * ExplainOneQuery -
 *	  print out the execution plan for one query
 */
static void
154
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
B
Bruce Momjian 已提交
155 156
{
	Plan	   *plan;
157
	QueryDesc  *queryDesc;
158 159
	bool		isCursor = false;
	int			cursorOptions = 0;
B
Bruce Momjian 已提交
160

161 162 163
	/* planner will not cope with utility statements */
	if (query->commandType == CMD_UTILITY)
	{
164 165 166 167 168 169 170 171 172 173 174
		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);
175 176
			/* get locks (we assume ExplainQuery already copied tree) */
			AcquireRewriteLocks(query);
177
			rewritten = QueryRewrite(query);
178
			if (list_length(rewritten) != 1)
179
				elog(ERROR, "unexpected rewrite result");
180
			query = (Query *) linitial(rewritten);
181 182 183 184 185 186
			Assert(query->commandType == CMD_SELECT);
			/* do not actually execute the underlying query! */
			stmt->analyze = false;
		}
		else if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
		{
187
			do_text_output_oneline(tstate, "NOTIFY");
188 189
			return;
		}
190
		else
191
		{
192
			do_text_output_oneline(tstate, "UTILITY");
193 194
			return;
		}
195 196
	}

197
	/* plan the query */
198
	plan = planner(query, isCursor, cursorOptions, NULL);
B
Bruce Momjian 已提交
199

200
	/* Create a QueryDesc requesting no output */
201 202 203
	queryDesc = CreateQueryDesc(query, plan,
								ActiveSnapshot, InvalidSnapshot,
								None_Receiver, NULL,
204 205
								stmt->analyze);

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
	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)
{
223
	instr_time  starttime;
224 225 226 227
	double		totaltime = 0;
	ExplainState *es;
	StringInfo	str;

228
	INSTR_TIME_SET_CURRENT(starttime);
229

230 231 232 233
	/* If analyzing, we need to cope with queued triggers */
	if (stmt->analyze)
		AfterTriggerBeginQuery();

234
	/* call ExecutorStart to prepare the plan for execution */
235
	ExecutorStart(queryDesc, !stmt->analyze);
236

237
	/* Execute the plan for statistics if asked for */
238
	if (stmt->analyze)
239
	{
240 241
		/* run the plan */
		ExecutorRun(queryDesc, ForwardScanDirection, 0L);
242

243 244
		/* We can't clean up 'till we're done printing the stats... */
		totaltime += elapsed_time(&starttime);
245 246
	}

247
	es = (ExplainState *) palloc0(sizeof(ExplainState));
B
Bruce Momjian 已提交
248

249
	es->printCost = true;		/* default */
250 251
	es->printNodes = stmt->verbose;
	es->printAnalyze = stmt->analyze;
252
	es->rtable = queryDesc->parsetree->rtable;
253 254

	if (es->printNodes)
255
	{
256
		char	   *s;
257
		char	   *f;
258

259
		s = nodeToString(queryDesc->plantree);
260 261
		if (s)
		{
262 263 264 265
			if (Explain_pretty_print)
				f = pretty_format_node_dump(s);
			else
				f = format_node_dump(s);
266
			pfree(s);
267 268 269
			do_text_output_multiline(tstate, f);
			pfree(f);
			if (es->printCost)
B
Bruce Momjian 已提交
270
				do_text_output_oneline(tstate, "");		/* separator line */
271 272
		}
	}
273

274 275
	str = makeStringInfo();

276 277
	if (es->printCost)
	{
278
		explain_outNode(str, queryDesc->plantree, queryDesc->planstate,
279 280 281 282
						NULL, 0, es);
	}

	/*
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
	 * If we ran the command, run any AFTER triggers it queued.  (Note this
	 * will not include DEFERRED triggers; since those don't run until end of
	 * transaction, we can't measure them.)  Include into total runtime.
	 */
	if (stmt->analyze)
	{
		INSTR_TIME_SET_CURRENT(starttime);
		AfterTriggerEndQuery(queryDesc->estate);
		totaltime += elapsed_time(&starttime);
	}

	/* Print info about runtime of triggers */
	if (es->printAnalyze)
	{
		ResultRelInfo *rInfo;
		int		numrels = queryDesc->estate->es_num_result_relations;
		int		nr;

		rInfo = queryDesc->estate->es_result_relations;
		for (nr = 0; nr < numrels; rInfo++, nr++)
		{
			int		nt;

306
			if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
				continue;
			for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
			{
				Trigger *trig = rInfo->ri_TrigDesc->triggers + nt;
				Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
				char   *conname;

				/* Must clean up instrumentation state */
				InstrEndLoop(instr);

				/*
				 * We ignore triggers that were never invoked; they likely
				 * aren't relevant to the current query type.
				 */
				if (instr->ntuples == 0)
					continue;

				if (trig->tgisconstraint &&
					(conname = GetConstraintNameForTrigger(trig->tgoid)) != NULL)
				{
					appendStringInfo(str, "Trigger for constraint %s",
									 conname);
					pfree(conname);
				}
				else
					appendStringInfo(str, "Trigger %s", trig->tgname);

				if (numrels > 1)
					appendStringInfo(str, " on %s",
									 RelationGetRelationName(rInfo->ri_RelationDesc));

				appendStringInfo(str, ": time=%.3f calls=%.0f\n",
								 1000.0 * instr->total,
								 instr->ntuples);
			}
		}
	}

	/*
	 * Close down the query and free resources.  Include time for this
	 * in the total runtime (although it should be pretty minimal).
348
	 */
349
	INSTR_TIME_SET_CURRENT(starttime);
350

351
	ExecutorEnd(queryDesc);
352

353 354
	FreeQueryDesc(queryDesc);

355 356 357
	/* We need a CCI just in case query expanded to multiple plans */
	if (stmt->analyze)
		CommandCounterIncrement();
358 359 360 361 362

	totaltime += elapsed_time(&starttime);

	if (es->printCost)
	{
363
		if (stmt->analyze)
364
			appendStringInfo(str, "Total runtime: %.3f ms\n",
365
							 1000.0 * totaltime);
366
		do_text_output_multiline(tstate, str->data);
B
Bruce Momjian 已提交
367
	}
368

369 370
	pfree(str->data);
	pfree(str);
B
Bruce Momjian 已提交
371
	pfree(es);
372 373
}

374
/* Compute elapsed time in seconds since given timestamp */
375
static double
376
elapsed_time(instr_time *starttime)
377
{
378
	instr_time endtime;
379

380
	INSTR_TIME_SET_CURRENT(endtime);
381

382
#ifndef WIN32
383 384 385 386 387 388 389
	endtime.tv_sec -= starttime->tv_sec;
	endtime.tv_usec -= starttime->tv_usec;
	while (endtime.tv_usec < 0)
	{
		endtime.tv_usec += 1000000;
		endtime.tv_sec--;
	}
390 391 392 393 394
#else  /* WIN32 */
	endtime.QuadPart -= starttime->QuadPart;
#endif

	return INSTR_TIME_GET_DOUBLE(endtime);
395
}
396 397 398

/*
 * explain_outNode -
399 400
 *	  converts a Plan node into ascii string and appends it to 'str'
 *
401 402 403 404
 * 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.
 *
405 406 407
 * 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.
408 409
 */
static void
410
explain_outNode(StringInfo str,
411
				Plan *plan, PlanState *planstate,
412
				Plan *outer_plan,
413
				int indent, ExplainState *es)
414
{
B
Bruce Momjian 已提交
415 416
	char	   *pname;
	int			i;
417 418 419

	if (plan == NULL)
	{
420
		appendStringInfoChar(str, '\n');
421 422 423 424 425
		return;
	}

	switch (nodeTag(plan))
	{
426 427 428 429 430 431
		case T_Result:
			pname = "Result";
			break;
		case T_Append:
			pname = "Append";
			break;
432 433 434 435 436 437
		case T_BitmapAnd:
			pname = "BitmapAnd";
			break;
		case T_BitmapOr:
			pname = "BitmapOr";
			break;
438
		case T_NestLoop:
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
			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;
			}
460 461
			break;
		case T_MergeJoin:
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
			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;
			}
483 484
			break;
		case T_HashJoin:
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
			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;
			}
506 507 508 509 510 511 512
			break;
		case T_SeqScan:
			pname = "Seq Scan";
			break;
		case T_IndexScan:
			pname = "Index Scan";
			break;
513 514 515 516 517 518
		case T_BitmapIndexScan:
			pname = "Bitmap Index Scan";
			break;
		case T_BitmapHeapScan:
			pname = "Bitmap Heap Scan";
			break;
519 520 521 522 523 524
		case T_TidScan:
			pname = "Tid Scan";
			break;
		case T_SubqueryScan:
			pname = "Subquery Scan";
			break;
525 526 527
		case T_FunctionScan:
			pname = "Function Scan";
			break;
528 529 530
		case T_Material:
			pname = "Materialize";
			break;
531 532 533 534 535 536 537
		case T_Sort:
			pname = "Sort";
			break;
		case T_Group:
			pname = "Group";
			break;
		case T_Agg:
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
			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;
			}
553 554 555 556
			break;
		case T_Unique:
			pname = "Unique";
			break;
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
		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;
577 578 579
		case T_Limit:
			pname = "Limit";
			break;
580 581 582 583
		case T_Hash:
			pname = "Hash";
			break;
		default:
584
			pname = "???";
585
			break;
586 587
	}

588
	appendStringInfoString(str, pname);
589 590
	switch (nodeTag(plan))
	{
591
		case T_IndexScan:
592
			if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
593
				appendStringInfoString(str, " Backward");
594 595
			appendStringInfo(str, " using %s",
							 quote_identifier(get_rel_name(((IndexScan *) plan)->indexid)));
596
			/* FALL THRU */
597
		case T_SeqScan:
598
		case T_BitmapHeapScan:
599
		case T_TidScan:
600 601
			if (((Scan *) plan)->scanrelid > 0)
			{
602 603
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
604
				char	   *relname;
605 606

				/* Assume it's on a real relation */
607
				Assert(rte->rtekind == RTE_RELATION);
608 609 610

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

612
				appendStringInfo(str, " on %s",
613
								 quote_identifier(relname));
614
				if (strcmp(rte->eref->aliasname, relname) != 0)
615
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
616
								 quote_identifier(rte->eref->aliasname));
617 618
			}
			break;
619 620
		case T_BitmapIndexScan:
			appendStringInfo(str, " on %s",
621
							 quote_identifier(get_rel_name(((BitmapIndexScan *) plan)->indexid)));
622
			break;
623 624 625 626 627 628 629
		case T_SubqueryScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);

				appendStringInfo(str, " %s",
630
								 quote_identifier(rte->eref->aliasname));
631 632
			}
			break;
633 634 635 636 637
		case T_FunctionScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
638
				char	   *proname;
639 640 641 642

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

643 644 645
				/*
				 * If the expression is still a function call, we can get
				 * the real name of the function.  Otherwise, punt (this
B
Bruce Momjian 已提交
646 647
				 * can happen if the optimizer simplified away the
				 * function call, for example).
648 649 650 651 652 653 654 655 656 657 658
				 */
				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;
659 660 661 662 663

				appendStringInfo(str, " on %s",
								 quote_identifier(proname));
				if (strcmp(rte->eref->aliasname, proname) != 0)
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
664
								 quote_identifier(rte->eref->aliasname));
665 666
			}
			break;
667 668
		default:
			break;
669 670 671
	}
	if (es->printCost)
	{
672 673 674
		appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
						 plan->startup_cost, plan->total_cost,
						 plan->plan_rows, plan->plan_width);
675

676 677 678 679
		/*
		 * We have to forcibly clean up the instrumentation state because
		 * we haven't done ExecutorEnd yet.  This is pretty grotty ...
		 */
680 681
		if (planstate->instrument)
			InstrEndLoop(planstate->instrument);
682 683

		if (planstate->instrument && planstate->instrument->nloops > 0)
684
		{
685
			double		nloops = planstate->instrument->nloops;
686

687
			appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
B
Bruce Momjian 已提交
688 689
						1000.0 * planstate->instrument->startup / nloops,
						  1000.0 * planstate->instrument->total / nloops,
690 691
							 planstate->instrument->ntuples / nloops,
							 planstate->instrument->nloops);
692
		}
693
		else if (es->printAnalyze)
694
			appendStringInfo(str, " (never executed)");
695
	}
696
	appendStringInfoChar(str, '\n');
697

698
	/* quals, sort keys, etc */
699 700 701
	switch (nodeTag(plan))
	{
		case T_IndexScan:
702
			show_scan_qual(((IndexScan *) plan)->indexqualorig,
703
						   "Index Cond",
704
						   ((Scan *) plan)->scanrelid,
705
						   outer_plan,
706
						   str, indent, es);
707
			show_scan_qual(plan->qual,
708
						   "Filter",
709
						   ((Scan *) plan)->scanrelid,
710
						   outer_plan,
711 712
						   str, indent, es);
			break;
713
		case T_BitmapIndexScan:
714
			show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
715 716 717 718 719 720 721
						   "Index Cond",
						   ((Scan *) plan)->scanrelid,
						   outer_plan,
						   str, indent, es);
			break;
		case T_BitmapHeapScan:
			/* XXX do we want to show this in production? */
722
			show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
723 724 725 726 727
						   "Recheck Cond",
						   ((Scan *) plan)->scanrelid,
						   outer_plan,
						   str, indent, es);
			/* FALL THRU */
728 729
		case T_SeqScan:
		case T_TidScan:
730
		case T_SubqueryScan:
731
		case T_FunctionScan:
732
			show_scan_qual(plan->qual,
733
						   "Filter",
734
						   ((Scan *) plan)->scanrelid,
735
						   outer_plan,
736 737 738
						   str, indent, es);
			break;
		case T_NestLoop:
739
			show_upper_qual(((NestLoop *) plan)->join.joinqual,
740
							"Join Filter",
741 742 743
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
744 745
			show_upper_qual(plan->qual,
							"Filter",
746 747 748 749 750
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_MergeJoin:
751 752
			show_upper_qual(((MergeJoin *) plan)->mergeclauses,
							"Merge Cond",
753 754 755
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
756
			show_upper_qual(((MergeJoin *) plan)->join.joinqual,
757
							"Join Filter",
758 759 760
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
761 762
			show_upper_qual(plan->qual,
							"Filter",
763 764 765 766 767
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_HashJoin:
768 769
			show_upper_qual(((HashJoin *) plan)->hashclauses,
							"Hash Cond",
770 771 772
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
773
			show_upper_qual(((HashJoin *) plan)->join.joinqual,
774
							"Join Filter",
775 776 777
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
778 779
			show_upper_qual(plan->qual,
							"Filter",
780 781 782 783 784 785
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_Agg:
		case T_Group:
786 787
			show_upper_qual(plan->qual,
							"Filter",
788 789 790 791
							"subplan", 0, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
792
		case T_Sort:
793 794 795
			show_sort_keys(plan->targetlist,
						   ((Sort *) plan)->numCols,
						   ((Sort *) plan)->sortColIdx,
796 797 798
						   "Sort Key",
						   str, indent, es);
			break;
799 800
		case T_Result:
			show_upper_qual((List *) ((Result *) plan)->resconstantqual,
801
							"One-Time Filter",
802 803 804
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
805 806
			show_upper_qual(plan->qual,
							"Filter",
807 808 809 810 811 812 813 814
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
		default:
			break;
	}

V
Vadim B. Mikheev 已提交
815 816 817
	/* initPlan-s */
	if (plan->initPlan)
	{
818
		List	   *saved_rtable = es->rtable;
819
		ListCell   *lst;
820

B
Bruce Momjian 已提交
821
		for (i = 0; i < indent; i++)
V
Vadim B. Mikheev 已提交
822 823
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  InitPlan\n");
824
		foreach(lst, planstate->initPlan)
V
Vadim B. Mikheev 已提交
825
		{
826
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
827
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
828

829
			es->rtable = sp->rtable;
V
Vadim B. Mikheev 已提交
830 831 832
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
833 834
			explain_outNode(str, sp->plan,
							sps->planstate,
835
							NULL,
836
							indent + 4, es);
V
Vadim B. Mikheev 已提交
837 838 839
		}
		es->rtable = saved_rtable;
	}
840 841 842 843 844 845

	/* lefttree */
	if (outerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
846
		appendStringInfo(str, "  ->  ");
847 848 849 850 851
		/*
		 * Ordinarily we don't pass down our own outer_plan value to our
		 * child nodes, but in bitmap scan trees we must, since the bottom
		 * BitmapIndexScan nodes may have outer references.
		 */
852 853
		explain_outNode(str, outerPlan(plan),
						outerPlanState(planstate),
854
						IsA(plan, BitmapHeapScan) ? outer_plan : NULL,
855
						indent + 3, es);
856
	}
857 858 859 860 861 862

	/* righttree */
	if (innerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
863
		appendStringInfo(str, "  ->  ");
864 865 866
		explain_outNode(str, innerPlan(plan),
						innerPlanState(planstate),
						outerPlan(plan),
867
						indent + 3, es);
V
Vadim B. Mikheev 已提交
868
	}
869

870
	if (IsA(plan, Append))
871
	{
872
		Append	   *appendplan = (Append *) plan;
873
		AppendState *appendstate = (AppendState *) planstate;
874
		ListCell   *lst;
875
		int			j;
876

877
		j = 0;
878 879
		foreach(lst, appendplan->appendplans)
		{
880
			Plan	   *subnode = (Plan *) lfirst(lst);
881 882 883

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

886 887 888 889 890
			explain_outNode(str, subnode,
							appendstate->appendplans[j],
							NULL,
							indent + 3, es);
			j++;
891 892
		}
	}
893

894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
	if (IsA(plan, BitmapAnd))
	{
		BitmapAnd	   *bitmapandplan = (BitmapAnd *) plan;
		BitmapAndState *bitmapandstate = (BitmapAndState *) planstate;
		ListCell   *lst;
		int			j;

		j = 0;
		foreach(lst, bitmapandplan->bitmapplans)
		{
			Plan	   *subnode = (Plan *) lfirst(lst);

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

			explain_outNode(str, subnode,
							bitmapandstate->bitmapplans[j],
912
							outer_plan,	/* pass down same outer plan */
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
							indent + 3, es);
			j++;
		}
	}

	if (IsA(plan, BitmapOr))
	{
		BitmapOr	   *bitmaporplan = (BitmapOr *) plan;
		BitmapOrState *bitmaporstate = (BitmapOrState *) planstate;
		ListCell   *lst;
		int			j;

		j = 0;
		foreach(lst, bitmaporplan->bitmapplans)
		{
			Plan	   *subnode = (Plan *) lfirst(lst);

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

			explain_outNode(str, subnode,
							bitmaporstate->bitmapplans[j],
936
							outer_plan,	/* pass down same outer plan */
937 938 939 940 941
							indent + 3, es);
			j++;
		}
	}

942 943 944
	if (IsA(plan, SubqueryScan))
	{
		SubqueryScan *subqueryscan = (SubqueryScan *) plan;
945
		SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
946 947 948 949 950
		Plan	   *subnode = subqueryscan->subplan;
		RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
									  es->rtable);
		List	   *saved_rtable = es->rtable;

951
		Assert(rte->rtekind == RTE_SUBQUERY);
952 953 954 955 956 957
		es->rtable = rte->subquery->rtable;

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

958 959 960 961
		explain_outNode(str, subnode,
						subquerystate->subplan,
						NULL,
						indent + 3, es);
962 963 964 965 966

		es->rtable = saved_rtable;
	}

	/* subPlan-s */
967
	if (planstate->subPlan)
968 969
	{
		List	   *saved_rtable = es->rtable;
970
		ListCell   *lst;
971 972 973 974

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  SubPlan\n");
975
		foreach(lst, planstate->subPlan)
976
		{
977
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
978
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
979 980

			es->rtable = sp->rtable;
981 982 983
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
984 985 986
			explain_outNode(str, sp->plan,
							sps->planstate,
							NULL,
987 988 989 990
							indent + 4, es);
		}
		es->rtable = saved_rtable;
	}
991 992
}

993 994 995 996
/*
 * Show a qualifier expression for a scan plan node
 */
static void
997
show_scan_qual(List *qual, const char *qlabel,
998
			   int scanrelid, Plan *outer_plan,
999 1000 1001
			   StringInfo str, int indent, ExplainState *es)
{
	RangeTblEntry *rte;
1002 1003
	Node	   *scancontext;
	Node	   *outercontext;
1004 1005 1006 1007 1008 1009 1010 1011 1012
	List	   *context;
	Node	   *node;
	char	   *exprstr;
	int			i;

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

1013 1014
	/* Convert AND list to explicit AND */
	node = (Node *) make_ands_explicit(qual);
1015

1016
	/* Generate deparse context */
1017
	Assert(scanrelid > 0 && scanrelid <= list_length(es->rtable));
1018
	rte = rt_fetch(scanrelid, es->rtable);
1019
	scancontext = deparse_context_for_rte(rte);
1020 1021 1022

	/*
	 * If we have an outer plan that is referenced by the qual, add it to
B
Bruce Momjian 已提交
1023 1024
	 * the deparse context.  If not, don't (so that we don't force
	 * prefixes unnecessarily).
1025 1026 1027
	 */
	if (outer_plan)
	{
B
Bruce Momjian 已提交
1028
		Relids		varnos = pull_varnos(node);
1029 1030

		if (bms_is_member(OUTER, varnos))
1031
			outercontext = deparse_context_for_subplan("outer",
B
Bruce Momjian 已提交
1032
												  outer_plan->targetlist,
1033 1034 1035
													   es->rtable);
		else
			outercontext = NULL;
1036
		bms_free(varnos);
1037
	}
1038
	else
1039 1040 1041
		outercontext = NULL;

	context = deparse_context_for_plan(scanrelid, scancontext,
1042 1043
									   OUTER, outercontext,
									   NIL);
1044 1045

	/* Deparse the expression */
1046
	exprstr = deparse_expression(node, context, (outercontext != NULL), false);
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087

	/* 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,
1088 1089
									   inner_varno, innercontext,
									   NIL);
1090 1091 1092

	/* Deparse the expression */
	node = (Node *) make_ands_explicit(qual);
1093
	exprstr = deparse_expression(node, context, (inner_plan != NULL), false);
1094 1095 1096 1097 1098 1099 1100

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

1101 1102 1103 1104
/*
 * Show the sort keys for a Sort node.
 */
static void
1105 1106
show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
			   const char *qlabel,
1107 1108 1109 1110 1111 1112
			   StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
	bool		useprefix;
	int			keyno;
	char	   *exprstr;
1113
	Relids		varnos;
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
	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 已提交
1125 1126 1127 1128 1129
	 * 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.
1130
	 */
1131 1132
	varnos = pull_varnos((Node *) tlist);
	if (bms_is_member(0, varnos))
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
	{
		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);
1149
		useprefix = list_length(es->rtable) > 1;
1150
	}
1151
	bms_free(varnos);
1152

1153
	for (keyno = 0; keyno < nkeys; keyno++)
1154 1155
	{
		/* find key expression in tlist */
1156
		AttrNumber	keyresno = keycols[keyno];
1157
		TargetEntry *target = get_tle_by_resno(tlist, keyresno);
1158

1159
		if (!target)
1160
			elog(ERROR, "no tlist entry for key %d", keyresno);
1161 1162 1163 1164 1165 1166
		/* 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 已提交
1167
		appendStringInfoString(str, exprstr);
1168 1169 1170 1171
	}

	appendStringInfo(str, "\n");
}