explain.c 25.0 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * explain.c
4
 *	  Explain query execution plans
5
 *
B
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994-5, Regents of the University of California
8
 *
9
 * IDENTIFICATION
N
Neil Conway 已提交
10
 *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.119 2004/01/31 05:09:40 neilc 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 "executor/executor.h"
22
#include "executor/instrument.h"
B
Bruce Momjian 已提交
23 24
#include "lib/stringinfo.h"
#include "nodes/print.h"
25
#include "optimizer/clauses.h"
26
#include "optimizer/planner.h"
27
#include "optimizer/var.h"
B
Bruce Momjian 已提交
28
#include "parser/parsetree.h"
29
#include "rewrite/rewriteHandler.h"
30
#include "tcop/pquery.h"
31
#include "utils/builtins.h"
32
#include "utils/guc.h"
33
#include "utils/lsyscache.h"
34

35

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

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

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

77
	/* prepare for projection of tuples */
78
	tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
79

80 81
	if (query->commandType == CMD_UTILITY)
	{
82
		/* Rewriter will not cope with utility statements */
83 84 85
		if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt))
			ExplainOneQuery(query, stmt, tstate);
		else if (query->utilityStmt && IsA(query->utilityStmt, ExecuteStmt))
86 87 88
			ExplainExecuteQuery(stmt, tstate);
		else
			do_text_output_oneline(tstate, "Utility statements have no plan structure");
89
	}
90
	else
B
Bruce Momjian 已提交
91
	{
92 93 94 95 96 97
		/* Rewrite through rule system */
		rewritten = QueryRewrite(query);

		if (rewritten == NIL)
		{
			/* In the case of an INSTEAD NOTHING, tell at least that */
98
			do_text_output_oneline(tstate, "Query rewrites to nothing");
99 100 101 102 103 104 105 106 107
		}
		else
		{
			/* Explain every plan */
			foreach(l, rewritten)
			{
				ExplainOneQuery(lfirst(l), stmt, tstate);
				/* put a blank line between plans */
				if (lnext(l) != NIL)
108
					do_text_output_oneline(tstate, "");
109 110
			}
		}
B
Bruce Momjian 已提交
111 112
	}

113
	end_tup_output(tstate);
B
Bruce Momjian 已提交
114 115
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/*
 * 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",
					   TEXTOID, -1, 0, false);
	return tupdesc;
}

B
Bruce Momjian 已提交
132 133 134 135 136
/*
 * ExplainOneQuery -
 *	  print out the execution plan for one query
 */
static void
137
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
B
Bruce Momjian 已提交
138 139
{
	Plan	   *plan;
140
	QueryDesc  *queryDesc;
141 142
	bool		isCursor = false;
	int			cursorOptions = 0;
B
Bruce Momjian 已提交
143

144 145 146
	/* planner will not cope with utility statements */
	if (query->commandType == CMD_UTILITY)
	{
147 148 149 150 151 152 153 154 155 156 157 158 159
		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);
			if (length(rewritten) != 1)
160
				elog(ERROR, "unexpected rewrite result");
161 162 163 164 165 166 167
			query = (Query *) lfirst(rewritten);
			Assert(query->commandType == CMD_SELECT);
			/* do not actually execute the underlying query! */
			stmt->analyze = false;
		}
		else if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
		{
168
			do_text_output_oneline(tstate, "NOTIFY");
169 170
			return;
		}
171
		else
172
		{
173
			do_text_output_oneline(tstate, "UTILITY");
174 175
			return;
		}
176 177
	}

178
	/* plan the query */
179
	plan = planner(query, isCursor, cursorOptions);
B
Bruce Momjian 已提交
180

181
	/* Create a QueryDesc requesting no output */
182
	queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
183 184
								stmt->analyze);

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
	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);

209
	/* call ExecutorStart to prepare the plan for execution */
210
	ExecutorStart(queryDesc, false, !stmt->analyze);
211

212
	/* Execute the plan for statistics if asked for */
213
	if (stmt->analyze)
214
	{
215 216
		/* run the plan */
		ExecutorRun(queryDesc, ForwardScanDirection, 0L);
217

218 219
		/* We can't clean up 'till we're done printing the stats... */
		totaltime += elapsed_time(&starttime);
220 221
	}

222
	es = (ExplainState *) palloc0(sizeof(ExplainState));
B
Bruce Momjian 已提交
223

224
	es->printCost = true;		/* default */
225 226
	es->printNodes = stmt->verbose;
	es->printAnalyze = stmt->analyze;
227
	es->rtable = queryDesc->parsetree->rtable;
228 229

	if (es->printNodes)
230
	{
231
		char	   *s;
232
		char	   *f;
233

234
		s = nodeToString(queryDesc->plantree);
235 236
		if (s)
		{
237 238 239 240
			if (Explain_pretty_print)
				f = pretty_format_node_dump(s);
			else
				f = format_node_dump(s);
241
			pfree(s);
242 243 244
			do_text_output_multiline(tstate, f);
			pfree(f);
			if (es->printCost)
B
Bruce Momjian 已提交
245
				do_text_output_oneline(tstate, "");		/* separator line */
246 247
		}
	}
248

249 250
	str = makeStringInfo();

251 252
	if (es->printCost)
	{
253
		explain_outNode(str, queryDesc->plantree, queryDesc->planstate,
254 255 256 257
						NULL, 0, es);
	}

	/*
B
Bruce Momjian 已提交
258 259
	 * Close down the query and free resources.  Include time for this in
	 * the total runtime.
260 261
	 */
	gettimeofday(&starttime, NULL);
262

263
	ExecutorEnd(queryDesc);
264 265
	FreeQueryDesc(queryDesc);

266 267 268 269 270 271
	CommandCounterIncrement();

	totaltime += elapsed_time(&starttime);

	if (es->printCost)
	{
272
		if (stmt->analyze)
273
			appendStringInfo(str, "Total runtime: %.3f ms\n",
274
							 1000.0 * totaltime);
275
		do_text_output_multiline(tstate, str->data);
B
Bruce Momjian 已提交
276
	}
277

278 279
	pfree(str->data);
	pfree(str);
B
Bruce Momjian 已提交
280
	pfree(es);
281 282
}

283 284
/* Compute elapsed time in seconds since given gettimeofday() timestamp */
static double
B
Bruce Momjian 已提交
285
elapsed_time(struct timeval * starttime)
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
{
	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;
}
301 302 303

/*
 * explain_outNode -
304 305
 *	  converts a Plan node into ascii string and appends it to 'str'
 *
306 307 308 309
 * 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.
 *
310 311 312
 * 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.
313 314
 */
static void
315
explain_outNode(StringInfo str,
316
				Plan *plan, PlanState *planstate,
317
				Plan *outer_plan,
318
				int indent, ExplainState *es)
319
{
B
Bruce Momjian 已提交
320 321 322
	List	   *l;
	char	   *pname;
	int			i;
323 324 325

	if (plan == NULL)
	{
326
		appendStringInfoChar(str, '\n');
327 328 329 330 331
		return;
	}

	switch (nodeTag(plan))
	{
332 333 334 335 336 337 338
		case T_Result:
			pname = "Result";
			break;
		case T_Append:
			pname = "Append";
			break;
		case T_NestLoop:
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
			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;
			}
360 361
			break;
		case T_MergeJoin:
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
			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;
			}
383 384
			break;
		case T_HashJoin:
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
			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;
			}
406 407 408 409 410 411 412
			break;
		case T_SeqScan:
			pname = "Seq Scan";
			break;
		case T_IndexScan:
			pname = "Index Scan";
			break;
413 414 415 416 417 418
		case T_TidScan:
			pname = "Tid Scan";
			break;
		case T_SubqueryScan:
			pname = "Subquery Scan";
			break;
419 420 421
		case T_FunctionScan:
			pname = "Function Scan";
			break;
422 423 424
		case T_Material:
			pname = "Materialize";
			break;
425 426 427 428 429 430 431
		case T_Sort:
			pname = "Sort";
			break;
		case T_Group:
			pname = "Group";
			break;
		case T_Agg:
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
			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;
			}
447 448 449 450
			break;
		case T_Unique:
			pname = "Unique";
			break;
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
		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;
471 472 473
		case T_Limit:
			pname = "Limit";
			break;
474 475 476 477
		case T_Hash:
			pname = "Hash";
			break;
		default:
478
			pname = "???";
479
			break;
480 481
	}

482
	appendStringInfoString(str, pname);
483 484
	switch (nodeTag(plan))
	{
485
		case T_IndexScan:
486
			if (ScanDirectionIsBackward(((IndexScan *) plan)->indxorderdir))
487 488
				appendStringInfoString(str, " Backward");
			appendStringInfoString(str, " using ");
V
Vadim B. Mikheev 已提交
489
			i = 0;
B
Bruce Momjian 已提交
490
			foreach(l, ((IndexScan *) plan)->indxid)
V
Vadim B. Mikheev 已提交
491
			{
492 493
				Relation	relation;

494
				relation = index_open(lfirsto(l));
495 496
				appendStringInfo(str, "%s%s",
								 (++i > 1) ? ", " : "",
B
Bruce Momjian 已提交
497
					quote_identifier(RelationGetRelationName(relation)));
498
				index_close(relation);
V
Vadim B. Mikheev 已提交
499
			}
500
			/* FALL THRU */
501
		case T_SeqScan:
502
		case T_TidScan:
503 504
			if (((Scan *) plan)->scanrelid > 0)
			{
505 506
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
507
				char	   *relname;
508 509

				/* Assume it's on a real relation */
510
				Assert(rte->rtekind == RTE_RELATION);
511 512 513

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

515
				appendStringInfo(str, " on %s",
516
								 quote_identifier(relname));
517
				if (strcmp(rte->eref->aliasname, relname) != 0)
518
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
519
								 quote_identifier(rte->eref->aliasname));
520 521 522 523 524 525 526 527 528
			}
			break;
		case T_SubqueryScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);

				appendStringInfo(str, " %s",
529
								 quote_identifier(rte->eref->aliasname));
530 531
			}
			break;
532 533 534 535 536
		case T_FunctionScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
537
				char	   *proname;
538 539 540 541

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

542 543 544
				/*
				 * If the expression is still a function call, we can get
				 * the real name of the function.  Otherwise, punt (this
B
Bruce Momjian 已提交
545 546
				 * can happen if the optimizer simplified away the
				 * function call, for example).
547 548 549 550 551 552 553 554 555 556 557
				 */
				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;
558 559 560 561 562

				appendStringInfo(str, " on %s",
								 quote_identifier(proname));
				if (strcmp(rte->eref->aliasname, proname) != 0)
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
563
								 quote_identifier(rte->eref->aliasname));
564 565
			}
			break;
566 567
		default:
			break;
568 569 570
	}
	if (es->printCost)
	{
571 572 573
		appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
						 plan->startup_cost, plan->total_cost,
						 plan->plan_rows, plan->plan_width);
574

575 576 577 578 579 580 581
		/*
		 * 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)
582
		{
583
			double		nloops = planstate->instrument->nloops;
584

585
			appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
B
Bruce Momjian 已提交
586 587
						1000.0 * planstate->instrument->startup / nloops,
						  1000.0 * planstate->instrument->total / nloops,
588 589
							 planstate->instrument->ntuples / nloops,
							 planstate->instrument->nloops);
590
		}
591
		else if (es->printAnalyze)
592
			appendStringInfo(str, " (never executed)");
593
	}
594
	appendStringInfoChar(str, '\n');
595

596
	/* quals, sort keys, etc */
597 598 599 600
	switch (nodeTag(plan))
	{
		case T_IndexScan:
			show_scan_qual(((IndexScan *) plan)->indxqualorig, true,
601
						   "Index Cond",
602
						   ((Scan *) plan)->scanrelid,
603
						   outer_plan,
604
						   str, indent, es);
605 606
			show_scan_qual(plan->qual, false,
						   "Filter",
607
						   ((Scan *) plan)->scanrelid,
608
						   outer_plan,
609 610 611 612
						   str, indent, es);
			break;
		case T_SeqScan:
		case T_TidScan:
613
		case T_SubqueryScan:
614
		case T_FunctionScan:
615 616
			show_scan_qual(plan->qual, false,
						   "Filter",
617
						   ((Scan *) plan)->scanrelid,
618
						   outer_plan,
619 620 621
						   str, indent, es);
			break;
		case T_NestLoop:
622
			show_upper_qual(((NestLoop *) plan)->join.joinqual,
623
							"Join Filter",
624 625 626
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
627 628
			show_upper_qual(plan->qual,
							"Filter",
629 630 631 632 633
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_MergeJoin:
634 635
			show_upper_qual(((MergeJoin *) plan)->mergeclauses,
							"Merge Cond",
636 637 638
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
639
			show_upper_qual(((MergeJoin *) plan)->join.joinqual,
640
							"Join Filter",
641 642 643
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
644 645
			show_upper_qual(plan->qual,
							"Filter",
646 647 648 649 650
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_HashJoin:
651 652
			show_upper_qual(((HashJoin *) plan)->hashclauses,
							"Hash Cond",
653 654 655
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
656
			show_upper_qual(((HashJoin *) plan)->join.joinqual,
657
							"Join Filter",
658 659 660
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
661 662
			show_upper_qual(plan->qual,
							"Filter",
663 664 665 666 667 668
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_Agg:
		case T_Group:
669 670
			show_upper_qual(plan->qual,
							"Filter",
671 672 673 674
							"subplan", 0, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
675
		case T_Sort:
676 677 678
			show_sort_keys(plan->targetlist,
						   ((Sort *) plan)->numCols,
						   ((Sort *) plan)->sortColIdx,
679 680 681
						   "Sort Key",
						   str, indent, es);
			break;
682 683
		case T_Result:
			show_upper_qual((List *) ((Result *) plan)->resconstantqual,
684
							"One-Time Filter",
685 686 687
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
688 689
			show_upper_qual(plan->qual,
							"Filter",
690 691 692 693 694 695 696 697
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
		default:
			break;
	}

V
Vadim B. Mikheev 已提交
698 699 700
	/* initPlan-s */
	if (plan->initPlan)
	{
701 702 703
		List	   *saved_rtable = es->rtable;
		List	   *lst;

B
Bruce Momjian 已提交
704
		for (i = 0; i < indent; i++)
V
Vadim B. Mikheev 已提交
705 706
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  InitPlan\n");
707
		foreach(lst, planstate->initPlan)
V
Vadim B. Mikheev 已提交
708
		{
709
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
710
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
711

712
			es->rtable = sp->rtable;
V
Vadim B. Mikheev 已提交
713 714 715
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
716 717
			explain_outNode(str, sp->plan,
							sps->planstate,
718
							NULL,
719
							indent + 4, es);
V
Vadim B. Mikheev 已提交
720 721 722
		}
		es->rtable = saved_rtable;
	}
723 724 725 726 727 728

	/* lefttree */
	if (outerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
729
		appendStringInfo(str, "  ->  ");
730 731 732 733
		explain_outNode(str, outerPlan(plan),
						outerPlanState(planstate),
						NULL,
						indent + 3, es);
734
	}
735 736 737 738 739 740

	/* righttree */
	if (innerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
741
		appendStringInfo(str, "  ->  ");
742 743 744
		explain_outNode(str, innerPlan(plan),
						innerPlanState(planstate),
						outerPlan(plan),
745
						indent + 3, es);
V
Vadim B. Mikheev 已提交
746
	}
747

748
	if (IsA(plan, Append))
749
	{
750
		Append	   *appendplan = (Append *) plan;
751
		AppendState *appendstate = (AppendState *) planstate;
752
		List	   *lst;
753
		int			j;
754

755
		j = 0;
756 757
		foreach(lst, appendplan->appendplans)
		{
758
			Plan	   *subnode = (Plan *) lfirst(lst);
759 760 761

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

764 765 766 767 768
			explain_outNode(str, subnode,
							appendstate->appendplans[j],
							NULL,
							indent + 3, es);
			j++;
769 770
		}
	}
771 772 773 774

	if (IsA(plan, SubqueryScan))
	{
		SubqueryScan *subqueryscan = (SubqueryScan *) plan;
775
		SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
776 777 778 779 780
		Plan	   *subnode = subqueryscan->subplan;
		RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
									  es->rtable);
		List	   *saved_rtable = es->rtable;

781
		Assert(rte->rtekind == RTE_SUBQUERY);
782 783 784 785 786 787
		es->rtable = rte->subquery->rtable;

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

788 789 790 791
		explain_outNode(str, subnode,
						subquerystate->subplan,
						NULL,
						indent + 3, es);
792 793 794 795 796

		es->rtable = saved_rtable;
	}

	/* subPlan-s */
797
	if (planstate->subPlan)
798 799 800 801 802 803 804
	{
		List	   *saved_rtable = es->rtable;
		List	   *lst;

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  SubPlan\n");
805
		foreach(lst, planstate->subPlan)
806
		{
807
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
808
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
809 810

			es->rtable = sp->rtable;
811 812 813
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
814 815 816
			explain_outNode(str, sp->plan,
							sps->planstate,
							NULL,
817 818 819 820
							indent + 4, es);
		}
		es->rtable = saved_rtable;
	}
821 822
}

823 824 825 826 827
/*
 * Show a qualifier expression for a scan plan node
 */
static void
show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
828
			   int scanrelid, Plan *outer_plan,
829 830 831
			   StringInfo str, int indent, ExplainState *es)
{
	RangeTblEntry *rte;
832 833
	Node	   *scancontext;
	Node	   *outercontext;
834 835 836 837 838 839 840 841 842 843 844 845 846 847
	List	   *context;
	Node	   *node;
	char	   *exprstr;
	int			i;

	/* No work if empty qual */
	if (qual == NIL)
		return;
	if (is_or_qual)
	{
		if (lfirst(qual) == NIL && lnext(qual) == NIL)
			return;
	}

848 849 850 851 852 853
	/* Fix qual --- indexqual requires different processing */
	if (is_or_qual)
		node = make_ors_ands_explicit(qual);
	else
		node = (Node *) make_ands_explicit(qual);

854 855 856
	/* Generate deparse context */
	Assert(scanrelid > 0 && scanrelid <= length(es->rtable));
	rte = rt_fetch(scanrelid, es->rtable);
857
	scancontext = deparse_context_for_rte(rte);
858 859 860

	/*
	 * If we have an outer plan that is referenced by the qual, add it to
B
Bruce Momjian 已提交
861 862
	 * the deparse context.  If not, don't (so that we don't force
	 * prefixes unnecessarily).
863 864 865
	 */
	if (outer_plan)
	{
B
Bruce Momjian 已提交
866
		Relids		varnos = pull_varnos(node);
867 868

		if (bms_is_member(OUTER, varnos))
869
			outercontext = deparse_context_for_subplan("outer",
B
Bruce Momjian 已提交
870
												  outer_plan->targetlist,
871 872 873
													   es->rtable);
		else
			outercontext = NULL;
874
		bms_free(varnos);
875
	}
876
	else
877 878 879
		outercontext = NULL;

	context = deparse_context_for_plan(scanrelid, scancontext,
880 881
									   OUTER, outercontext,
									   NIL);
882 883

	/* Deparse the expression */
884
	exprstr = deparse_expression(node, context, (outercontext != NULL), false);
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925

	/* 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,
926 927
									   inner_varno, innercontext,
									   NIL);
928 929 930

	/* Deparse the expression */
	node = (Node *) make_ands_explicit(qual);
931
	exprstr = deparse_expression(node, context, (inner_plan != NULL), false);
932 933 934 935 936 937 938

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

939 940 941 942
/*
 * Show the sort keys for a Sort node.
 */
static void
943 944
show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
			   const char *qlabel,
945 946 947 948 949 950
			   StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
	bool		useprefix;
	int			keyno;
	char	   *exprstr;
951
	Relids		varnos;
952 953 954 955 956 957 958 959 960 961 962
	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 已提交
963 964 965 966 967
	 * 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.
968
	 */
969 970
	varnos = pull_varnos((Node *) tlist);
	if (bms_is_member(0, varnos))
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
	{
		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);
		useprefix = length(es->rtable) > 1;
	}
989
	bms_free(varnos);
990

991
	for (keyno = 0; keyno < nkeys; keyno++)
992 993
	{
		/* find key expression in tlist */
994
		AttrNumber	keyresno = keycols[keyno];
995
		TargetEntry *target = get_tle_by_resno(tlist, keyresno);
996

997
		if (!target)
998
			elog(ERROR, "no tlist entry for key %d", keyresno);
999 1000 1001 1002 1003 1004
		/* 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 已提交
1005
		appendStringInfoString(str, exprstr);
1006 1007 1008 1009 1010
	}

	appendStringInfo(str, "\n");
}

1011
/*
B
Bruce Momjian 已提交
1012
 * Indexscan qual lists have an implicit OR-of-ANDs structure.	Make it
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
 * explicit so deparsing works properly.
 */
static Node *
make_ors_ands_explicit(List *orclauses)
{
	if (orclauses == NIL)
		return NULL;			/* probably can't happen */
	else if (lnext(orclauses) == NIL)
		return (Node *) make_ands_explicit(lfirst(orclauses));
	else
	{
1024
		FastList	args;
B
Bruce Momjian 已提交
1025
		List	   *orptr;
1026

1027
		FastListInit(&args);
1028
		foreach(orptr, orclauses)
1029
			FastAppend(&args, make_ands_explicit(lfirst(orptr)));
1030

1031
		return (Node *) make_orclause(FastListValue(&args));
1032 1033
	}
}