@@ -107,38 +107,18 @@ fn projection_above_limit(plan: &LogicalPlan) -> Result<LogicalPlan> {
107107 }
108108}
109109
110- /// A `Vec<Column>` -- or, when we don't need that, a `()`.
111- trait ColumnCollector {
112- fn push ( & mut self , column : & Column ) ;
113- }
114-
115- impl ColumnCollector for ( ) {
116- fn push ( & mut self , _column : & Column ) { }
117- }
118-
119- impl ColumnCollector for Vec < Column > {
120- fn push ( & mut self , column : & Column ) {
121- self . push ( column. clone ( ) ) ;
122- }
123- }
124-
125110#[ derive( Default ) ]
126- struct ColumnRecorder < T : ColumnCollector > {
127- column_hash : HashSet < Column > ,
128- /// The purpose is to store a `Vec<Column>` in the order that the columns were seen, so that
129- /// the intermediate projection layer looks "natural" instead of having columns in some sorted
130- /// order or nondeterministic hash table ordering.
131- collector : T ,
111+ struct ColumnRecorder {
112+ /// We use indexmap IndexSet because we want iteration order to be deterministic and
113+ /// specifically, to match left-to-right insertion order.
114+ columns : indexmap:: IndexSet < Column > ,
132115}
133116
134- impl < T : ColumnCollector > ExpressionVisitor for ColumnRecorder < T > {
117+ impl ExpressionVisitor for ColumnRecorder {
135118 fn pre_visit ( mut self , expr : & Expr ) -> Result < Recursion < Self > > {
136119 match expr {
137120 Expr :: Column ( c) => {
138- let inserted = self . column_hash . insert ( c. clone ( ) ) ;
139- if inserted {
140- self . collector . push ( c) ;
141- }
121+ self . columns . insert ( c. clone ( ) ) ;
142122 }
143123 Expr :: ScalarVariable ( _var_names) => {
144124 // expr_to_columns, with its ColumnNameVisitor includes ScalarVariable for some
@@ -203,7 +183,7 @@ fn looks_expensive(ex: &Expr) -> Result<bool> {
203183
204184fn lift_up_expensive_projections (
205185 plan : & LogicalPlan ,
206- used_columns : ColumnRecorder < ( ) > ,
186+ used_columns : ColumnRecorder ,
207187) -> Result < ( LogicalPlan , Option < Vec < Expr > > ) > {
208188 match plan {
209189 LogicalPlan :: Sort { expr, input } => {
@@ -231,10 +211,7 @@ fn lift_up_expensive_projections(
231211 input,
232212 schema,
233213 } => {
234- let mut column_recorder = ColumnRecorder :: < Vec < Column > > {
235- column_hash : HashSet :: new ( ) ,
236- collector : Vec :: new ( ) ,
237- } ;
214+ let mut column_recorder = ColumnRecorder :: default ( ) ;
238215
239216 let mut this_projection_exprs = Vec :: < usize > :: new ( ) ;
240217
@@ -260,7 +237,7 @@ fn lift_up_expensive_projections(
260237 already_retained_cols. push ( ( col. clone ( ) , Some ( alias. clone ( ) ) ) ) ;
261238 }
262239
263- if used_columns. column_hash . contains ( & field. qualified_column ( ) ) {
240+ if used_columns. columns . contains ( & field. qualified_column ( ) ) {
264241 pal_debug ! (
265242 "Expr {}: used_columns contains field {:?}" ,
266243 i,
@@ -315,7 +292,7 @@ fn lift_up_expensive_projections(
315292 let mut expensive_expr_column_replacements = Vec :: < ( Column , Column ) > :: new ( ) ;
316293
317294 let mut generated_col_number = 0 ;
318- let needed_columns = column_recorder. collector ;
295+ let needed_columns = column_recorder. columns ;
319296 ' outer: for col in needed_columns {
320297 pal_debug ! ( "Processing column {:?} in needed_columns" , col) ;
321298
0 commit comments