datafusion_substrait/logical_plan/consumer/expr/
mod.rs1mod aggregate_function;
19mod cast;
20mod field_reference;
21mod function_arguments;
22mod if_then;
23mod lambda;
24mod literal;
25mod nested;
26mod scalar_function;
27mod singular_or_list;
28mod subquery;
29mod window_function;
30
31pub use aggregate_function::*;
32pub use cast::*;
33pub use field_reference::*;
34pub use function_arguments::*;
35pub use if_then::*;
36pub use lambda::*;
37pub use literal::*;
38pub use nested::*;
39pub use scalar_function::*;
40pub use singular_or_list::*;
41pub use subquery::*;
42pub use window_function::*;
43
44use crate::extensions::Extensions;
45use crate::logical_plan::consumer::{
46 DefaultSubstraitConsumer, SubstraitConsumer, from_substrait_named_struct,
47 rename_field,
48};
49use datafusion::arrow::datatypes::Field;
50use datafusion::common::{DFSchema, DFSchemaRef, not_impl_err, plan_err, substrait_err};
51use datafusion::execution::SessionState;
52use datafusion::logical_expr::{Expr, ExprSchemable};
53use substrait::proto::expression::RexType;
54use substrait::proto::expression_reference::ExprType;
55use substrait::proto::{Expression, ExtendedExpression};
56
57pub async fn from_substrait_rex(
59 consumer: &impl SubstraitConsumer,
60 expression: &Expression,
61 input_schema: &DFSchema,
62) -> datafusion::common::Result<Expr> {
63 match &expression.rex_type {
64 Some(t) => match t {
65 RexType::Literal(expr) => consumer.consume_literal(expr).await,
66 RexType::Selection(expr) => {
67 consumer.consume_field_reference(expr, input_schema).await
68 }
69 RexType::ScalarFunction(expr) => {
70 consumer.consume_scalar_function(expr, input_schema).await
71 }
72 RexType::WindowFunction(expr) => {
73 consumer.consume_window_function(expr, input_schema).await
74 }
75 RexType::IfThen(expr) => consumer.consume_if_then(expr, input_schema).await,
76 RexType::SwitchExpression(expr) => {
77 consumer.consume_switch(expr, input_schema).await
78 }
79 RexType::SingularOrList(expr) => {
80 consumer.consume_singular_or_list(expr, input_schema).await
81 }
82
83 RexType::MultiOrList(expr) => {
84 consumer.consume_multi_or_list(expr, input_schema).await
85 }
86
87 RexType::Cast(expr) => {
88 consumer.consume_cast(expr.as_ref(), input_schema).await
89 }
90
91 RexType::Subquery(expr) => {
92 consumer.consume_subquery(expr.as_ref(), input_schema).await
93 }
94 RexType::Nested(expr) => consumer.consume_nested(expr, input_schema).await,
95 #[expect(deprecated)]
96 RexType::Enum(expr) => consumer.consume_enum(expr, input_schema).await,
97 RexType::DynamicParameter(expr) => {
98 consumer.consume_dynamic_parameter(expr, input_schema).await
99 }
100 RexType::Lambda(lambda) => {
101 consumer.consume_lambda(lambda.as_ref(), input_schema).await
102 }
103 RexType::LambdaInvocation(_) => {
104 not_impl_err!("Lambda invocations are not supported")
105 }
106 },
107 None => substrait_err!("Expression must set rex_type: {expression:?}"),
108 }
109}
110
111pub async fn from_substrait_extended_expr(
121 state: &SessionState,
122 extended_expr: &ExtendedExpression,
123) -> datafusion::common::Result<ExprContainer> {
124 let extensions = Extensions::try_from(&extended_expr.extensions)?;
126 if !extensions.type_variations.is_empty() {
127 return not_impl_err!("Type variation extensions are not supported");
128 }
129
130 let consumer = DefaultSubstraitConsumer::new(&extensions, state);
131
132 let input_schema = DFSchemaRef::new(match &extended_expr.base_schema {
133 Some(base_schema) => from_substrait_named_struct(&consumer, base_schema),
134 None => {
135 plan_err!(
136 "required property `base_schema` missing from Substrait ExtendedExpression message"
137 )
138 }
139 }?);
140
141 let mut exprs = Vec::with_capacity(extended_expr.referred_expr.len());
143 for (expr_idx, substrait_expr) in extended_expr.referred_expr.iter().enumerate() {
144 let scalar_expr = match &substrait_expr.expr_type {
145 Some(ExprType::Expression(scalar_expr)) => Ok(scalar_expr),
146 Some(ExprType::Measure(_)) => {
147 not_impl_err!("Measure expressions are not yet supported")
148 }
149 None => {
150 plan_err!(
151 "required property `expr_type` missing from Substrait ExpressionReference message"
152 )
153 }
154 }?;
155 let expr = consumer
156 .consume_expression(scalar_expr, &input_schema)
157 .await?;
158 let output_field = expr.to_field(&input_schema)?.1;
159 let mut names_idx = 0;
160 let output_field = rename_field(
161 &output_field,
162 &substrait_expr.output_names,
163 expr_idx,
164 &mut names_idx,
165 )?;
166 exprs.push((expr, output_field));
167 }
168
169 Ok(ExprContainer {
170 input_schema,
171 exprs,
172 })
173}
174
175pub struct ExprContainer {
182 pub input_schema: DFSchemaRef,
184 pub exprs: Vec<(Expr, Field)>,
188}
189
190pub async fn from_substrait_rex_vec(
192 consumer: &impl SubstraitConsumer,
193 exprs: &Vec<Expression>,
194 input_schema: &DFSchema,
195) -> datafusion::common::Result<Vec<Expr>> {
196 let mut expressions: Vec<Expr> = vec![];
197 for expr in exprs {
198 let expression = consumer.consume_expression(expr, input_schema).await?;
199 expressions.push(expression);
200 }
201 Ok(expressions)
202}
203
204#[cfg(test)]
205mod tests {
206 use crate::extensions::Extensions;
207 use crate::logical_plan::consumer::utils::tests::test_consumer;
208 use crate::logical_plan::consumer::*;
209 use datafusion::common::DFSchema;
210 use datafusion::logical_expr::Expr;
211 use substrait::proto::Expression;
212 use substrait::proto::expression::RexType;
213 use substrait::proto::expression::window_function::BoundsType;
214
215 #[tokio::test]
216 async fn window_function_with_range_unit_and_no_order_by()
217 -> datafusion::common::Result<()> {
218 let substrait = Expression {
219 rex_type: Some(RexType::WindowFunction(
220 substrait::proto::expression::WindowFunction {
221 function_reference: 0,
222 bounds_type: BoundsType::Range as i32,
223 sorts: vec![],
224 ..Default::default()
225 },
226 )),
227 };
228
229 let mut consumer = test_consumer();
230
231 let mut extensions = Extensions::default();
234 extensions.register_function("count");
235 consumer.extensions = &extensions;
236
237 match from_substrait_rex(&consumer, &substrait, &DFSchema::empty()).await? {
238 Expr::WindowFunction(window_function) => {
239 assert_eq!(window_function.params.order_by.len(), 1)
240 }
241 _ => panic!("expr was not a WindowFunction"),
242 };
243
244 Ok(())
245 }
246
247 #[tokio::test]
248 async fn window_function_with_count() -> datafusion::common::Result<()> {
249 let substrait = Expression {
250 rex_type: Some(RexType::WindowFunction(
251 substrait::proto::expression::WindowFunction {
252 function_reference: 0,
253 ..Default::default()
254 },
255 )),
256 };
257
258 let mut consumer = test_consumer();
259
260 let mut extensions = Extensions::default();
261 extensions.register_function("count");
262 consumer.extensions = &extensions;
263
264 match from_substrait_rex(&consumer, &substrait, &DFSchema::empty()).await? {
265 Expr::WindowFunction(window_function) => {
266 assert_eq!(window_function.params.args.len(), 1)
267 }
268 _ => panic!("expr was not a WindowFunction"),
269 };
270
271 Ok(())
272 }
273}