Skip to content

Commit 655aa5b

Browse files
committed
Now that plans have flat rangetable lists, it's a lot easier to get EXPLAIN to
drill down into subplan targetlists to print the referent expression for an OUTER or INNER var in an upper plan node. Hence, make it do that always, and banish the old hack of showing "?columnN?" when things got too complicated. Along the way, fix an EXPLAIN bug I introduced by suppressing subqueries from execution-time range tables: get_name_for_var_field() assumed it could look at rte->subquery to find out the real type of a RECORD var. That doesn't work anymore, but instead we can look at the input plan of the SubqueryScan plan node.
1 parent 9cc2a71 commit 655aa5b

File tree

4 files changed

+444
-457
lines changed

4 files changed

+444
-457
lines changed

src/backend/commands/explain.c

+51-130
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994-5, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.158 2007/02/22 23:44:24 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.159 2007/02/23 21:59:44 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -49,11 +49,9 @@ static void explain_outNode(StringInfo str,
4949
Plan *outer_plan,
5050
int indent, ExplainState *es);
5151
static void show_scan_qual(List *qual, const char *qlabel,
52-
int scanrelid, Plan *outer_plan,
52+
int scanrelid, Plan *outer_plan, Plan *inner_plan,
5353
StringInfo str, int indent, ExplainState *es);
54-
static void show_upper_qual(List *qual, const char *qlabel,
55-
const char *outer_name, Plan *outer_plan,
56-
const char *inner_name, Plan *inner_plan,
54+
static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
5755
StringInfo str, int indent, ExplainState *es);
5856
static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
5957
const char *qlabel,
@@ -725,37 +723,44 @@ explain_outNode(StringInfo str,
725723
show_scan_qual(((IndexScan *) plan)->indexqualorig,
726724
"Index Cond",
727725
((Scan *) plan)->scanrelid,
728-
outer_plan,
726+
outer_plan, NULL,
729727
str, indent, es);
730728
show_scan_qual(plan->qual,
731729
"Filter",
732730
((Scan *) plan)->scanrelid,
733-
outer_plan,
731+
outer_plan, NULL,
734732
str, indent, es);
735733
break;
736734
case T_BitmapIndexScan:
737735
show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
738736
"Index Cond",
739737
((Scan *) plan)->scanrelid,
740-
outer_plan,
738+
outer_plan, NULL,
741739
str, indent, es);
742740
break;
743741
case T_BitmapHeapScan:
744742
/* XXX do we want to show this in production? */
745743
show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
746744
"Recheck Cond",
747745
((Scan *) plan)->scanrelid,
748-
outer_plan,
746+
outer_plan, NULL,
749747
str, indent, es);
750748
/* FALL THRU */
751749
case T_SeqScan:
752-
case T_SubqueryScan:
753750
case T_FunctionScan:
754751
case T_ValuesScan:
752+
show_scan_qual(plan->qual,
753+
"Filter",
754+
((Scan *) plan)->scanrelid,
755+
outer_plan, NULL,
756+
str, indent, es);
757+
break;
758+
case T_SubqueryScan:
755759
show_scan_qual(plan->qual,
756760
"Filter",
757761
((Scan *) plan)->scanrelid,
758762
outer_plan,
763+
((SubqueryScan *) plan)->subplan,
759764
str, indent, es);
760765
break;
761766
case T_TidScan:
@@ -771,67 +776,49 @@ explain_outNode(StringInfo str,
771776
show_scan_qual(tidquals,
772777
"TID Cond",
773778
((Scan *) plan)->scanrelid,
774-
outer_plan,
779+
outer_plan, NULL,
775780
str, indent, es);
776781
show_scan_qual(plan->qual,
777782
"Filter",
778783
((Scan *) plan)->scanrelid,
779-
outer_plan,
784+
outer_plan, NULL,
780785
str, indent, es);
781786
}
782787
break;
783788
case T_NestLoop:
784789
show_upper_qual(((NestLoop *) plan)->join.joinqual,
785-
"Join Filter",
786-
"outer", outerPlan(plan),
787-
"inner", innerPlan(plan),
790+
"Join Filter", plan,
788791
str, indent, es);
789792
show_upper_qual(plan->qual,
790-
"Filter",
791-
"outer", outerPlan(plan),
792-
"inner", innerPlan(plan),
793+
"Filter", plan,
793794
str, indent, es);
794795
break;
795796
case T_MergeJoin:
796797
show_upper_qual(((MergeJoin *) plan)->mergeclauses,
797-
"Merge Cond",
798-
"outer", outerPlan(plan),
799-
"inner", innerPlan(plan),
798+
"Merge Cond", plan,
800799
str, indent, es);
801800
show_upper_qual(((MergeJoin *) plan)->join.joinqual,
802-
"Join Filter",
803-
"outer", outerPlan(plan),
804-
"inner", innerPlan(plan),
801+
"Join Filter", plan,
805802
str, indent, es);
806803
show_upper_qual(plan->qual,
807-
"Filter",
808-
"outer", outerPlan(plan),
809-
"inner", innerPlan(plan),
804+
"Filter", plan,
810805
str, indent, es);
811806
break;
812807
case T_HashJoin:
813808
show_upper_qual(((HashJoin *) plan)->hashclauses,
814-
"Hash Cond",
815-
"outer", outerPlan(plan),
816-
"inner", innerPlan(plan),
809+
"Hash Cond", plan,
817810
str, indent, es);
818811
show_upper_qual(((HashJoin *) plan)->join.joinqual,
819-
"Join Filter",
820-
"outer", outerPlan(plan),
821-
"inner", innerPlan(plan),
812+
"Join Filter", plan,
822813
str, indent, es);
823814
show_upper_qual(plan->qual,
824-
"Filter",
825-
"outer", outerPlan(plan),
826-
"inner", innerPlan(plan),
815+
"Filter", plan,
827816
str, indent, es);
828817
break;
829818
case T_Agg:
830819
case T_Group:
831820
show_upper_qual(plan->qual,
832-
"Filter",
833-
"subplan", outerPlan(plan),
834-
"", NULL,
821+
"Filter", plan,
835822
str, indent, es);
836823
break;
837824
case T_Sort:
@@ -843,14 +830,10 @@ explain_outNode(StringInfo str,
843830
break;
844831
case T_Result:
845832
show_upper_qual((List *) ((Result *) plan)->resconstantqual,
846-
"One-Time Filter",
847-
"subplan", outerPlan(plan),
848-
"", NULL,
833+
"One-Time Filter", plan,
849834
str, indent, es);
850835
show_upper_qual(plan->qual,
851-
"Filter",
852-
"subplan", outerPlan(plan),
853-
"", NULL,
836+
"Filter", plan,
854837
str, indent, es);
855838
break;
856839
default:
@@ -1032,14 +1015,18 @@ explain_outNode(StringInfo str,
10321015

10331016
/*
10341017
* Show a qualifier expression for a scan plan node
1018+
*
1019+
* Note: outer_plan is the referent for any OUTER vars in the scan qual;
1020+
* this would be the outer side of a nestloop plan. inner_plan should be
1021+
* NULL except for a SubqueryScan plan node, where it should be the subplan.
10351022
*/
10361023
static void
10371024
show_scan_qual(List *qual, const char *qlabel,
1038-
int scanrelid, Plan *outer_plan,
1025+
int scanrelid, Plan *outer_plan, Plan *inner_plan,
10391026
StringInfo str, int indent, ExplainState *es)
10401027
{
1041-
Node *outercontext;
10421028
List *context;
1029+
bool useprefix;
10431030
Node *node;
10441031
char *exprstr;
10451032
int i;
@@ -1051,31 +1038,14 @@ show_scan_qual(List *qual, const char *qlabel,
10511038
/* Convert AND list to explicit AND */
10521039
node = (Node *) make_ands_explicit(qual);
10531040

1054-
/*
1055-
* If we have an outer plan that is referenced by the qual, add it to the
1056-
* deparse context. If not, don't (so that we don't force prefixes
1057-
* unnecessarily).
1058-
*/
1059-
if (outer_plan)
1060-
{
1061-
Relids varnos = pull_varnos(node);
1062-
1063-
if (bms_is_member(OUTER, varnos))
1064-
outercontext = deparse_context_for_subplan("outer",
1065-
(Node *) outer_plan);
1066-
else
1067-
outercontext = NULL;
1068-
bms_free(varnos);
1069-
}
1070-
else
1071-
outercontext = NULL;
1072-
1073-
context = deparse_context_for_plan(OUTER, outercontext,
1074-
0, NULL,
1041+
/* Set up deparsing context */
1042+
context = deparse_context_for_plan((Node *) outer_plan,
1043+
(Node *) inner_plan,
10751044
es->rtable);
1045+
useprefix = (outer_plan != NULL || inner_plan != NULL);
10761046

10771047
/* Deparse the expression */
1078-
exprstr = deparse_expression(node, context, (outercontext != NULL), false);
1048+
exprstr = deparse_expression(node, context, useprefix, false);
10791049

10801050
/* And add to str */
10811051
for (i = 0; i < indent; i++)
@@ -1087,16 +1057,11 @@ show_scan_qual(List *qual, const char *qlabel,
10871057
* Show a qualifier expression for an upper-level plan node
10881058
*/
10891059
static void
1090-
show_upper_qual(List *qual, const char *qlabel,
1091-
const char *outer_name, Plan *outer_plan,
1092-
const char *inner_name, Plan *inner_plan,
1060+
show_upper_qual(List *qual, const char *qlabel, Plan *plan,
10931061
StringInfo str, int indent, ExplainState *es)
10941062
{
10951063
List *context;
1096-
Node *outercontext;
1097-
Node *innercontext;
1098-
int outer_varno;
1099-
int inner_varno;
1064+
bool useprefix;
11001065
Node *node;
11011066
char *exprstr;
11021067
int i;
@@ -1105,36 +1070,15 @@ show_upper_qual(List *qual, const char *qlabel,
11051070
if (qual == NIL)
11061071
return;
11071072

1108-
/* Generate deparse context */
1109-
if (outer_plan)
1110-
{
1111-
outercontext = deparse_context_for_subplan(outer_name,
1112-
(Node *) outer_plan);
1113-
outer_varno = OUTER;
1114-
}
1115-
else
1116-
{
1117-
outercontext = NULL;
1118-
outer_varno = 0;
1119-
}
1120-
if (inner_plan)
1121-
{
1122-
innercontext = deparse_context_for_subplan(inner_name,
1123-
(Node *) inner_plan);
1124-
inner_varno = INNER;
1125-
}
1126-
else
1127-
{
1128-
innercontext = NULL;
1129-
inner_varno = 0;
1130-
}
1131-
context = deparse_context_for_plan(outer_varno, outercontext,
1132-
inner_varno, innercontext,
1073+
/* Set up deparsing context */
1074+
context = deparse_context_for_plan((Node *) outerPlan(plan),
1075+
(Node *) innerPlan(plan),
11331076
es->rtable);
1077+
useprefix = list_length(es->rtable) > 1;
11341078

11351079
/* Deparse the expression */
11361080
node = (Node *) make_ands_explicit(qual);
1137-
exprstr = deparse_expression(node, context, (inner_plan != NULL), false);
1081+
exprstr = deparse_expression(node, context, useprefix, false);
11381082

11391083
/* And add to str */
11401084
for (i = 0; i < indent; i++)
@@ -1154,7 +1098,6 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
11541098
bool useprefix;
11551099
int keyno;
11561100
char *exprstr;
1157-
Relids varnos;
11581101
int i;
11591102

11601103
if (nkeys <= 0)
@@ -1164,33 +1107,11 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
11641107
appendStringInfo(str, " ");
11651108
appendStringInfo(str, " %s: ", qlabel);
11661109

1167-
/*
1168-
* In this routine we expect that the plan node's tlist has not been
1169-
* processed by set_plan_references(). Normally, any Vars will contain
1170-
* valid varnos referencing the actual rtable. But we might instead be
1171-
* looking at a dummy tlist generated by prepunion.c; if there are Vars
1172-
* with zero varno, use the tlist itself to determine their names.
1173-
*/
1174-
varnos = pull_varnos((Node *) sortplan->targetlist);
1175-
if (bms_is_member(0, varnos))
1176-
{
1177-
Node *outercontext;
1178-
1179-
outercontext = deparse_context_for_subplan("sort",
1180-
(Node *) sortplan);
1181-
context = deparse_context_for_plan(0, outercontext,
1182-
0, NULL,
1183-
es->rtable);
1184-
useprefix = false;
1185-
}
1186-
else
1187-
{
1188-
context = deparse_context_for_plan(0, NULL,
1189-
0, NULL,
1190-
es->rtable);
1191-
useprefix = list_length(es->rtable) > 1;
1192-
}
1193-
bms_free(varnos);
1110+
/* Set up deparsing context */
1111+
context = deparse_context_for_plan((Node *) outerPlan(sortplan),
1112+
NULL, /* Sort has no innerPlan */
1113+
es->rtable);
1114+
useprefix = list_length(es->rtable) > 1;
11941115

11951116
for (keyno = 0; keyno < nkeys; keyno++)
11961117
{

0 commit comments

Comments
 (0)