99
1010//! `EXPLAIN` support for structures defined in this crate.
1111
12- use std:: collections:: BTreeMap ;
12+ use std:: collections:: { BTreeMap , BTreeSet } ;
1313use std:: fmt:: Formatter ;
1414use std:: time:: Duration ;
1515
@@ -18,7 +18,7 @@ use mz_repr::GlobalId;
1818use mz_repr:: explain:: ExplainError :: LinearChainsPlusRecursive ;
1919use mz_repr:: explain:: text:: DisplayText ;
2020use mz_repr:: explain:: {
21- AnnotatedPlan , Explain , ExplainConfig , ExplainError , ExprHumanizer , ScalarOps ,
21+ AnnotatedPlan , Explain , ExplainConfig , ExplainError , ExprHumanizer , Indices , ScalarOps ,
2222 UnsupportedFormat , UsedIndexes ,
2323} ;
2424use mz_repr:: optimize:: OptimizerFeatures ;
@@ -93,18 +93,51 @@ where
9393 }
9494}
9595
96+ /// Carries metadata about the columns demanded from a source decoder.
97+ /// (Only emitted when a context flag is enabled.)
98+ #[ derive( Debug ) ]
99+ pub struct ProjectionInfo {
100+ /// Input columns demanded by the source MFP (filter + map + project).
101+ pub demand : Vec < usize > ,
102+ /// Total input arity, for deciding whether the demand is the identity.
103+ pub input_arity : usize ,
104+ }
105+
106+ impl < ' a , C , M > DisplayText < C > for HumanizedExpr < ' a , ProjectionInfo , M >
107+ where
108+ C : AsMut < Indent > ,
109+ M : HumanizerMode ,
110+ {
111+ fn fmt_text ( & self , f : & mut Formatter < ' _ > , ctx : & mut C ) -> std:: fmt:: Result {
112+ let ProjectionInfo {
113+ demand,
114+ input_arity,
115+ } = self . expr ;
116+
117+ // Suppress the annotation when every column is demanded — that's the
118+ // case where projection pushdown is a no-op.
119+ if demand. len ( ) == * input_arity {
120+ return Ok ( ( ) ) ;
121+ }
122+
123+ writeln ! ( f, "{}demand=({})" , ctx. as_mut( ) , Indices ( demand) )
124+ }
125+ }
126+
96127#[ allow( missing_debug_implementations) ]
97128pub struct ExplainSource < ' a > {
98129 pub id : GlobalId ,
99130 pub op : Option < & ' a MapFilterProject > ,
100131 pub pushdown_info : Option < PushdownInfo < ' a > > ,
132+ pub projection_info : Option < ProjectionInfo > ,
101133}
102134
103135impl < ' a > ExplainSource < ' a > {
104136 pub fn new (
105137 id : GlobalId ,
106138 op : Option < & ' a MapFilterProject > ,
107139 filter_pushdown : bool ,
140+ projection_pushdown : bool ,
108141 ) -> ExplainSource < ' a > {
109142 let pushdown_info = if filter_pushdown {
110143 op. map ( |op| {
@@ -121,10 +154,23 @@ impl<'a> ExplainSource<'a> {
121154 None
122155 } ;
123156
157+ let projection_info = if projection_pushdown {
158+ op. filter ( |op| !op. is_identity ( ) ) . map ( |op| {
159+ let demand: BTreeSet < usize > = op. demand ( ) ;
160+ ProjectionInfo {
161+ demand : demand. into_iter ( ) . collect ( ) ,
162+ input_arity : op. input_arity ,
163+ }
164+ } )
165+ } else {
166+ None
167+ } ;
168+
124169 ExplainSource {
125170 id,
126171 op,
127172 pushdown_info,
173+ projection_info,
128174 }
129175 }
130176
@@ -155,6 +201,9 @@ where
155201 if let Some ( pushdown_info) = & self . expr . pushdown_info {
156202 self . child ( pushdown_info) . fmt_text ( f, ctx) ?;
157203 }
204+ if let Some ( projection_info) = & self . expr . projection_info {
205+ self . child ( projection_info) . fmt_text ( f, ctx) ?;
206+ }
158207 Ok ( ( ) )
159208 } )
160209 }
0 commit comments