explain.c 21.7 KB
Newer Older
M
 
Marc G. Fournier 已提交
1
/*
2
 * explain.c
3
 *	  Explain the query execution plan
4
 *
B
Bruce Momjian 已提交
5
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1994-5, Regents of the University of California
7
 *
8
 * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.95 2002/12/06 19:28:03 tgl Exp $
9 10
 *
 */
11

12
#include "postgres.h"
M
Marc G. Fournier 已提交
13

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

32

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

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

/*
 * ExplainQuery -
63
 *	  execute an EXPLAIN command
64 65
 */
void
66
ExplainQuery(ExplainStmt *stmt, CommandDest dest)
67
{
68
	Query	   *query = stmt->query;
69 70
	TupOutputState *tstate;
	TupleDesc	tupdesc;
B
Bruce Momjian 已提交
71 72
	List	   *rewritten;
	List	   *l;
73

74
	/* need a tuple descriptor representing a single TEXT column */
75
	tupdesc = CreateTemplateTupleDesc(1, false);
76 77 78 79 80
	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
					   TEXTOID, -1, 0, false);

	/* prepare for projection of tuples */
	tstate = begin_tup_output_tupdesc(dest, tupdesc);
81

82 83
	if (query->commandType == CMD_UTILITY)
	{
84
		/* rewriter will not cope with utility statements */
85
		do_text_output_oneline(tstate, "Utility statements have no plan structure");
86
	}
87
	else
B
Bruce Momjian 已提交
88
	{
89 90 91 92 93 94
		/* Rewrite through rule system */
		rewritten = QueryRewrite(query);

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

110
	end_tup_output(tstate);
B
Bruce Momjian 已提交
111 112 113 114 115 116 117
}

/*
 * ExplainOneQuery -
 *	  print out the execution plan for one query
 */
static void
118
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
B
Bruce Momjian 已提交
119 120
{
	Plan	   *plan;
121
	QueryDesc  *queryDesc;
B
Bruce Momjian 已提交
122
	ExplainState *es;
123
	StringInfo	str;
124
	double		totaltime = 0;
125
	struct timeval starttime;
B
Bruce Momjian 已提交
126

127 128 129 130
	/* planner will not cope with utility statements */
	if (query->commandType == CMD_UTILITY)
	{
		if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
131
			do_text_output_oneline(tstate, "NOTIFY");
132
		else
133
			do_text_output_oneline(tstate, "UTILITY");
134 135 136
		return;
	}

137
	/* plan the query */
138
	plan = planner(query);
139

140 141 142
	/* pg_plan could have failed */
	if (plan == NULL)
		return;
B
Bruce Momjian 已提交
143

144 145 146 147 148 149 150 151 152 153 154 155
	/* We don't support DECLARE CURSOR here */
	Assert(!query->isPortal);

	gettimeofday(&starttime, NULL);

	/* Create a QueryDesc requesting no output */
	queryDesc = CreateQueryDesc(query, plan, None, NULL, NULL,
								stmt->analyze);

	/* call ExecutorStart to prepare the plan for execution */
	ExecutorStart(queryDesc);

156
	/* Execute the plan for statistics if asked for */
157
	if (stmt->analyze)
158
	{
159 160
		/* run the plan */
		ExecutorRun(queryDesc, ForwardScanDirection, 0L);
161

162
		/* We can't clean up 'till we're done printing the stats... */
163

164
		totaltime += elapsed_time(&starttime);
165 166
	}

167
	es = (ExplainState *) palloc0(sizeof(ExplainState));
B
Bruce Momjian 已提交
168

169
	es->printCost = true;		/* default */
170 171
	es->printNodes = stmt->verbose;
	es->printAnalyze = stmt->analyze;
172 173 174
	es->rtable = query->rtable;

	if (es->printNodes)
175
	{
176
		char	   *s;
177
		char	   *f;
178

179
		s = nodeToString(plan);
180 181
		if (s)
		{
182 183 184 185
			if (Explain_pretty_print)
				f = pretty_format_node_dump(s);
			else
				f = format_node_dump(s);
186
			pfree(s);
187 188 189
			do_text_output_multiline(tstate, f);
			pfree(f);
			if (es->printCost)
B
Bruce Momjian 已提交
190
				do_text_output_oneline(tstate, "");		/* separator line */
191 192
		}
	}
193

194 195
	str = makeStringInfo();

196 197
	if (es->printCost)
	{
198 199 200 201 202 203 204 205 206
		explain_outNode(str, plan, queryDesc->planstate,
						NULL, 0, es);
	}

	/*
	 * Close down the query and free resources.  Include time for this
	 * in the total runtime.
	 */
	gettimeofday(&starttime, NULL);
207

208 209 210 211 212 213 214
	ExecutorEnd(queryDesc);
	CommandCounterIncrement();

	totaltime += elapsed_time(&starttime);

	if (es->printCost)
	{
215
		if (stmt->analyze)
216 217
			appendStringInfo(str, "Total runtime: %.2f msec\n",
							 1000.0 * totaltime);
218
		do_text_output_multiline(tstate, str->data);
B
Bruce Momjian 已提交
219
	}
220

221 222
	pfree(str->data);
	pfree(str);
B
Bruce Momjian 已提交
223
	pfree(es);
224 225
}

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
/* Compute elapsed time in seconds since given gettimeofday() timestamp */
static double
elapsed_time(struct timeval *starttime)
{
	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;
}
244 245 246

/*
 * explain_outNode -
247 248
 *	  converts a Plan node into ascii string and appends it to 'str'
 *
249 250 251 252
 * 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.
 *
253 254 255
 * 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.
256 257
 */
static void
258 259 260
explain_outNode(StringInfo str,
				Plan *plan, PlanState *planstate,
				Plan *outer_plan,
261
				int indent, ExplainState *es)
262
{
B
Bruce Momjian 已提交
263 264 265
	List	   *l;
	char	   *pname;
	int			i;
266 267 268 269 270 271 272 273 274

	if (plan == NULL)
	{
		appendStringInfo(str, "\n");
		return;
	}

	switch (nodeTag(plan))
	{
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
		case T_Result:
			pname = "Result";
			break;
		case T_Append:
			pname = "Append";
			break;
		case T_NestLoop:
			pname = "Nested Loop";
			break;
		case T_MergeJoin:
			pname = "Merge Join";
			break;
		case T_HashJoin:
			pname = "Hash Join";
			break;
		case T_SeqScan:
			pname = "Seq Scan";
			break;
		case T_IndexScan:
			pname = "Index Scan";
			break;
296 297 298 299 300 301
		case T_TidScan:
			pname = "Tid Scan";
			break;
		case T_SubqueryScan:
			pname = "Subquery Scan";
			break;
302 303 304
		case T_FunctionScan:
			pname = "Function Scan";
			break;
305 306 307
		case T_Material:
			pname = "Materialize";
			break;
308 309 310 311 312 313 314
		case T_Sort:
			pname = "Sort";
			break;
		case T_Group:
			pname = "Group";
			break;
		case T_Agg:
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
			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;
			}
330 331 332 333
			break;
		case T_Unique:
			pname = "Unique";
			break;
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
		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;
354 355 356
		case T_Limit:
			pname = "Limit";
			break;
357 358 359 360
		case T_Hash:
			pname = "Hash";
			break;
		default:
361
			pname = "???";
362
			break;
363 364 365 366 367
	}

	appendStringInfo(str, pname);
	switch (nodeTag(plan))
	{
368
		case T_IndexScan:
369
			if (ScanDirectionIsBackward(((IndexScan *) plan)->indxorderdir))
370
				appendStringInfo(str, " Backward");
371
			appendStringInfo(str, " using ");
V
Vadim B. Mikheev 已提交
372
			i = 0;
B
Bruce Momjian 已提交
373
			foreach(l, ((IndexScan *) plan)->indxid)
V
Vadim B. Mikheev 已提交
374
			{
375 376 377
				Relation	relation;

				relation = index_open(lfirsti(l));
378 379
				appendStringInfo(str, "%s%s",
								 (++i > 1) ? ", " : "",
B
Bruce Momjian 已提交
380
					quote_identifier(RelationGetRelationName(relation)));
381
				index_close(relation);
V
Vadim B. Mikheev 已提交
382
			}
383
			/* FALL THRU */
384
		case T_SeqScan:
385
		case T_TidScan:
386 387
			if (((Scan *) plan)->scanrelid > 0)
			{
388 389
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
390
				char	   *relname;
391 392

				/* Assume it's on a real relation */
393
				Assert(rte->rtekind == RTE_RELATION);
394 395 396

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

398
				appendStringInfo(str, " on %s",
399
								 quote_identifier(relname));
400
				if (strcmp(rte->eref->aliasname, relname) != 0)
401
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
402
								 quote_identifier(rte->eref->aliasname));
403 404 405 406 407 408 409 410 411
			}
			break;
		case T_SubqueryScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);

				appendStringInfo(str, " %s",
412
								 quote_identifier(rte->eref->aliasname));
413 414
			}
			break;
415 416 417 418 419
		case T_FunctionScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
420 421 422 423
				Expr	   *expr;
				Func	   *funcnode;
				Oid			funcid;
				char	   *proname;
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438

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

				expr = (Expr *) rte->funcexpr;
				funcnode = (Func *) expr->oper;
				funcid = funcnode->funcid;

				/* We only show the func name, not schema name */
				proname = get_func_name(funcid);

				appendStringInfo(str, " on %s",
								 quote_identifier(proname));
				if (strcmp(rte->eref->aliasname, proname) != 0)
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
439
								 quote_identifier(rte->eref->aliasname));
440 441
			}
			break;
442 443
		default:
			break;
444 445 446
	}
	if (es->printCost)
	{
447 448 449
		appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
						 plan->startup_cost, plan->total_cost,
						 plan->plan_rows, plan->plan_width);
450

451 452 453 454 455 456 457
		/*
		 * 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)
458
		{
459
			double		nloops = planstate->instrument->nloops;
460 461

			appendStringInfo(str, " (actual time=%.2f..%.2f rows=%.0f loops=%.0f)",
462 463 464 465
							 1000.0 * planstate->instrument->startup / nloops,
							 1000.0 * planstate->instrument->total / nloops,
							 planstate->instrument->ntuples / nloops,
							 planstate->instrument->nloops);
466
		}
467
		else if (es->printAnalyze)
468 469
		{
			appendStringInfo(str, " (never executed)");
470
		}
471
	}
472
	appendStringInfo(str, "\n");
473

474
	/* quals, sort keys, etc */
475 476 477 478
	switch (nodeTag(plan))
	{
		case T_IndexScan:
			show_scan_qual(((IndexScan *) plan)->indxqualorig, true,
479
						   "Index Cond",
480
						   ((Scan *) plan)->scanrelid,
481
						   outer_plan,
482
						   str, indent, es);
483 484
			show_scan_qual(plan->qual, false,
						   "Filter",
485
						   ((Scan *) plan)->scanrelid,
486
						   outer_plan,
487 488 489 490
						   str, indent, es);
			break;
		case T_SeqScan:
		case T_TidScan:
491
		case T_SubqueryScan:
492
		case T_FunctionScan:
493 494
			show_scan_qual(plan->qual, false,
						   "Filter",
495
						   ((Scan *) plan)->scanrelid,
496
						   outer_plan,
497 498 499
						   str, indent, es);
			break;
		case T_NestLoop:
500
			show_upper_qual(((NestLoop *) plan)->join.joinqual,
501
							"Join Filter",
502 503 504
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
505 506
			show_upper_qual(plan->qual,
							"Filter",
507 508 509 510 511
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_MergeJoin:
512 513
			show_upper_qual(((MergeJoin *) plan)->mergeclauses,
							"Merge Cond",
514 515 516
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
517
			show_upper_qual(((MergeJoin *) plan)->join.joinqual,
518
							"Join Filter",
519 520 521
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
522 523
			show_upper_qual(plan->qual,
							"Filter",
524 525 526 527 528
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_HashJoin:
529 530
			show_upper_qual(((HashJoin *) plan)->hashclauses,
							"Hash Cond",
531 532 533
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
534
			show_upper_qual(((HashJoin *) plan)->join.joinqual,
535
							"Join Filter",
536 537 538
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
539 540
			show_upper_qual(plan->qual,
							"Filter",
541 542 543 544 545 546
							"outer", OUTER, outerPlan(plan),
							"inner", INNER, innerPlan(plan),
							str, indent, es);
			break;
		case T_Agg:
		case T_Group:
547 548
			show_upper_qual(plan->qual,
							"Filter",
549 550 551 552
							"subplan", 0, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
553 554 555 556 557
		case T_Sort:
			show_sort_keys(plan->targetlist, ((Sort *) plan)->keycount,
						   "Sort Key",
						   str, indent, es);
			break;
558 559
		case T_Result:
			show_upper_qual((List *) ((Result *) plan)->resconstantqual,
560
							"One-Time Filter",
561 562 563
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
564 565
			show_upper_qual(plan->qual,
							"Filter",
566 567 568 569 570 571 572 573
							"subplan", OUTER, outerPlan(plan),
							"", 0, NULL,
							str, indent, es);
			break;
		default:
			break;
	}

V
Vadim B. Mikheev 已提交
574 575 576
	/* initPlan-s */
	if (plan->initPlan)
	{
577
		List	   *saved_rtable = es->rtable;
578
		List	   *pslist = planstate->initPlan;
579 580
		List	   *lst;

B
Bruce Momjian 已提交
581
		for (i = 0; i < indent; i++)
V
Vadim B. Mikheev 已提交
582 583
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  InitPlan\n");
584
		foreach(lst, plan->initPlan)
V
Vadim B. Mikheev 已提交
585
		{
586 587 588 589
			SubPlan	   *subplan = (SubPlan *) lfirst(lst);
			SubPlanState *subplanstate = (SubPlanState *) lfirst(pslist);

			es->rtable = subplan->rtable;
V
Vadim B. Mikheev 已提交
590 591 592
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
593 594 595
			explain_outNode(str, subplan->plan,
							subplanstate->planstate,
							NULL,
596
							indent + 4, es);
597
			pslist = lnext(pslist);
V
Vadim B. Mikheev 已提交
598 599 600
		}
		es->rtable = saved_rtable;
	}
601 602 603 604 605 606

	/* lefttree */
	if (outerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
607
		appendStringInfo(str, "  ->  ");
608 609 610 611
		explain_outNode(str, outerPlan(plan),
						outerPlanState(planstate),
						NULL,
						indent + 3, es);
612
	}
613 614 615 616 617 618

	/* righttree */
	if (innerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
619
		appendStringInfo(str, "  ->  ");
620 621 622
		explain_outNode(str, innerPlan(plan),
						innerPlanState(planstate),
						outerPlan(plan),
623
						indent + 3, es);
V
Vadim B. Mikheev 已提交
624
	}
625

626
	if (IsA(plan, Append))
627
	{
628
		Append	   *appendplan = (Append *) plan;
629
		AppendState *appendstate = (AppendState *) planstate;
630
		List	   *lst;
631
		int			j;
632

633
		j = 0;
634 635
		foreach(lst, appendplan->appendplans)
		{
636
			Plan	   *subnode = (Plan *) lfirst(lst);
637 638 639

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

642 643 644 645 646
			explain_outNode(str, subnode,
							appendstate->appendplans[j],
							NULL,
							indent + 3, es);
			j++;
647 648
		}
	}
649 650 651 652

	if (IsA(plan, SubqueryScan))
	{
		SubqueryScan *subqueryscan = (SubqueryScan *) plan;
653
		SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
654 655 656 657 658
		Plan	   *subnode = subqueryscan->subplan;
		RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
									  es->rtable);
		List	   *saved_rtable = es->rtable;

659
		Assert(rte->rtekind == RTE_SUBQUERY);
660 661 662 663 664 665
		es->rtable = rte->subquery->rtable;

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

666 667 668 669
		explain_outNode(str, subnode,
						subquerystate->subplan,
						NULL,
						indent + 3, es);
670 671 672 673 674

		es->rtable = saved_rtable;
	}

	/* subPlan-s */
675
	if (planstate->subPlan)
676 677 678 679 680 681 682
	{
		List	   *saved_rtable = es->rtable;
		List	   *lst;

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  SubPlan\n");
683
		foreach(lst, planstate->subPlan)
684
		{
685 686 687 688
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
			SubPlan *sp = (SubPlan *) sps->ps.plan;

			es->rtable = sp->rtable;
689 690 691
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
692 693 694
			explain_outNode(str, sp->plan,
							sps->planstate,
							NULL,
695 696 697 698
							indent + 4, es);
		}
		es->rtable = saved_rtable;
	}
699 700
}

701 702 703 704 705
/*
 * Show a qualifier expression for a scan plan node
 */
static void
show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
706
			   int scanrelid, Plan *outer_plan,
707 708 709
			   StringInfo str, int indent, ExplainState *es)
{
	RangeTblEntry *rte;
710 711
	Node	   *scancontext;
	Node	   *outercontext;
712 713 714 715 716 717 718 719 720 721 722 723 724 725
	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;
	}

726 727 728 729 730 731
	/* Fix qual --- indexqual requires different processing */
	if (is_or_qual)
		node = make_ors_ands_explicit(qual);
	else
		node = (Node *) make_ands_explicit(qual);

732 733 734
	/* Generate deparse context */
	Assert(scanrelid > 0 && scanrelid <= length(es->rtable));
	rte = rt_fetch(scanrelid, es->rtable);
735
	scancontext = deparse_context_for_rte(rte);
736 737 738

	/*
	 * If we have an outer plan that is referenced by the qual, add it to
B
Bruce Momjian 已提交
739 740
	 * the deparse context.  If not, don't (so that we don't force
	 * prefixes unnecessarily).
741 742 743 744 745
	 */
	if (outer_plan)
	{
		if (intMember(OUTER, pull_varnos(node)))
			outercontext = deparse_context_for_subplan("outer",
B
Bruce Momjian 已提交
746
												  outer_plan->targetlist,
747 748 749 750
													   es->rtable);
		else
			outercontext = NULL;
	}
751
	else
752 753 754
		outercontext = NULL;

	context = deparse_context_for_plan(scanrelid, scancontext,
755 756
									   OUTER, outercontext,
									   NIL);
757 758

	/* Deparse the expression */
759
	exprstr = deparse_expression(node, context, (outercontext != NULL), false);
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800

	/* 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,
801 802
									   inner_varno, innercontext,
									   NIL);
803 804 805

	/* Deparse the expression */
	node = (Node *) make_ands_explicit(qual);
806
	exprstr = deparse_expression(node, context, (inner_plan != NULL), false);
807 808 809 810 811 812 813

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

814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
/*
 * Show the sort keys for a Sort node.
 */
static void
show_sort_keys(List *tlist, int nkeys, const char *qlabel,
			   StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
	bool		useprefix;
	int			keyno;
	List	   *tl;
	char	   *exprstr;
	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 已提交
837 838 839 840 841
	 * 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.
842
	 */
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
	if (intMember(0, pull_varnos((Node *) tlist)))
	{
		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;
	}
862 863 864 865 866 867 868 869 870 871

	for (keyno = 1; keyno <= nkeys; keyno++)
	{
		/* find key expression in tlist */
		foreach(tl, tlist)
		{
			TargetEntry *target = (TargetEntry *) lfirst(tl);

			if (target->resdom->reskey == keyno)
			{
872 873 874
				/* Deparse the expression, showing any top-level cast */
				exprstr = deparse_expression(target->expr, context,
											 useprefix, true);
875 876 877 878 879 880 881 882 883 884 885 886 887 888
				/* And add to str */
				if (keyno > 1)
					appendStringInfo(str, ", ");
				appendStringInfo(str, "%s", exprstr);
				break;
			}
		}
		if (tl == NIL)
			elog(ERROR, "show_sort_keys: no tlist entry for key %d", keyno);
	}

	appendStringInfo(str, "\n");
}

889
/*
B
Bruce Momjian 已提交
890
 * Indexscan qual lists have an implicit OR-of-ANDs structure.	Make it
891 892 893 894 895 896 897 898 899 900 901
 * 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
	{
B
Bruce Momjian 已提交
902 903
		List	   *args = NIL;
		List	   *orptr;
904 905 906 907 908 909 910

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

		return (Node *) make_orclause(args);
	}
}