@@ -26,7 +26,7 @@ use arrow::datatypes::{DataType, Field, IntervalUnit, Schema};
2626use crate :: analyzer:: AnalyzerRule ;
2727use crate :: utils:: NamePreserver ;
2828use datafusion_common:: config:: ConfigOptions ;
29- use datafusion_common:: tree_node:: { Transformed , TreeNode , TreeNodeRewriter } ;
29+ use datafusion_common:: tree_node:: { Transformed , TreeNode , TreeNodeIterator , TreeNodeRewriter } ;
3030use datafusion_common:: {
3131 exec_err, internal_err, not_impl_err, plan_datafusion_err, plan_err, Column ,
3232 DFSchema , DFSchemaRef , DataFusionError , Result , ScalarValue , TableReference ,
@@ -50,9 +50,7 @@ use datafusion_expr::type_coercion::other::{
5050use datafusion_expr:: type_coercion:: { is_datetime, is_utf8_or_large_utf8} ;
5151use datafusion_expr:: utils:: merge_schema;
5252use datafusion_expr:: {
53- is_false, is_not_false, is_not_true, is_not_unknown, is_true, is_unknown, not,
54- AggregateUDF , Expr , ExprFunctionExt , ExprSchemable , Join , LogicalPlan , Operator ,
55- Projection , ScalarUDF , Union , WindowFrame , WindowFrameBound , WindowFrameUnits ,
53+ is_false, is_not_false, is_not_true, is_not_unknown, is_true, is_unknown, not, AggregateUDF , Expr , ExprFunctionExt , ExprSchemable , Extension , Join , LogicalPlan , Operator , Projection , ScalarUDF , Union , WindowFrame , WindowFrameBound , WindowFrameUnits
5654} ;
5755
5856/// Performs type coercion by determining the schema
@@ -146,7 +144,37 @@ fn analyze_internal(
146144 // some plans need extra coercion after their expressions are coerced
147145 . map_data ( |plan| expr_rewrite. coerce_plan ( plan) ) ?
148146 // recompute the schema after the expressions have been rewritten as the types may have changed
149- . map_data ( |plan| plan. recompute_schema ( ) )
147+ . map_data ( |plan| plan. recompute_schema ( ) ) ?
148+ // Cube extension: Map "upper" expressions (after this node's output schema has been recomputed)
149+ . transform_data ( |plan| {
150+ match & plan {
151+ LogicalPlan :: Extension ( Extension { node } ) => {
152+ let upper_expressions = node. upper_expressions ( ) ;
153+ if upper_expressions. is_empty ( ) {
154+ Ok ( Transformed :: no ( plan) )
155+ } else {
156+ let output_schema = plan. schema ( ) . clone ( ) ;
157+ let mut upper_expr_rewrite = TypeCoercionRewriter :: new ( & output_schema) ;
158+ upper_expressions. into_iter ( ) . map_until_stop_and_collect ( |expr| {
159+ // No need for name preserver on upper expressions. (Why? Because
160+ // upper_expressions cannot change the output schema -- they use the output
161+ // schema, already defined by the node, as input. (They are filter
162+ // expressions.))
163+ expr. rewrite ( & mut upper_expr_rewrite)
164+ } ) ?
165+ . map_data ( |upper_expressions| {
166+ let new_node = node. with_upper_expressions ( upper_expressions) ?;
167+ if let Some ( new_node) = new_node {
168+ Ok ( LogicalPlan :: Extension ( Extension { node : new_node } ) )
169+ } else {
170+ internal_err ! ( "with_upper_expressions must not return None when upper_expressions() was non-empty" )
171+ }
172+ } )
173+ }
174+ } ,
175+ _ => Ok ( Transformed :: no ( plan) )
176+ }
177+ } )
150178}
151179
152180/// Rewrite expressions to apply type coercion.
0 commit comments