@@ -28,9 +28,9 @@ use datafusion_expr::{
28
28
CreateMemoryTable , DdlStatement , Distinct , Expr , LogicalPlan , LogicalPlanBuilder ,
29
29
} ;
30
30
use sqlparser:: ast:: {
31
- Expr as SQLExpr , Ident , LimitClause , Offset , OffsetRows , OrderBy , OrderByExpr ,
32
- OrderByKind , PipeOperator , Query , SelectInto , SetExpr , SetOperator , SetQuantifier ,
33
- TableAlias ,
31
+ Expr as SQLExpr , ExprWithAliasAndOrderBy , Ident , LimitClause , Offset , OffsetRows ,
32
+ OrderBy , OrderByExpr , OrderByKind , PipeOperator , Query , SelectInto , SetExpr ,
33
+ SetOperator , SetQuantifier , TableAlias ,
34
34
} ;
35
35
use sqlparser:: tokenizer:: Span ;
36
36
@@ -190,6 +190,15 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
190
190
queries,
191
191
planner_context,
192
192
) ,
193
+ PipeOperator :: Aggregate {
194
+ full_table_exprs,
195
+ group_by_expr,
196
+ } => self . pipe_operator_aggregate (
197
+ plan,
198
+ full_table_exprs,
199
+ group_by_expr,
200
+ planner_context,
201
+ ) ,
193
202
194
203
x => not_impl_err ! ( "`{x}` pipe operator is not supported yet" ) ,
195
204
}
@@ -296,6 +305,76 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
296
305
}
297
306
}
298
307
308
+ /// Handle AGGREGATE pipe operator
309
+ fn pipe_operator_aggregate (
310
+ & self ,
311
+ plan : LogicalPlan ,
312
+ full_table_exprs : Vec < ExprWithAliasAndOrderBy > ,
313
+ group_by_expr : Vec < ExprWithAliasAndOrderBy > ,
314
+ planner_context : & mut PlannerContext ,
315
+ ) -> Result < LogicalPlan > {
316
+ // Convert aggregate expressions directly
317
+ let aggr_exprs: Vec < Expr > = full_table_exprs
318
+ . into_iter ( )
319
+ . map ( |expr_with_alias_and_order_by| {
320
+ let expr_with_alias = expr_with_alias_and_order_by. expr ;
321
+ let sql_expr = expr_with_alias. expr ;
322
+ let alias = expr_with_alias. alias ;
323
+
324
+ // Convert SQL expression to DataFusion expression
325
+ let df_expr =
326
+ self . sql_to_expr ( sql_expr, plan. schema ( ) , planner_context) ?;
327
+
328
+ // Apply alias if present, but handle the case where the expression might already be aliased
329
+ match alias {
330
+ Some ( alias_ident) => {
331
+ // If the expression is already an alias, replace the alias name
332
+ match df_expr {
333
+ Expr :: Alias ( alias_expr) => {
334
+ Ok ( alias_expr. expr . alias ( alias_ident. value ) )
335
+ }
336
+ _ => Ok ( df_expr. alias ( alias_ident. value ) ) ,
337
+ }
338
+ }
339
+ None => Ok ( df_expr) ,
340
+ }
341
+ } )
342
+ . collect :: < Result < Vec < _ > > > ( ) ?;
343
+
344
+ // Convert group by expressions directly
345
+ let group_by_exprs: Vec < Expr > = group_by_expr
346
+ . into_iter ( )
347
+ . map ( |expr_with_alias_and_order_by| {
348
+ let expr_with_alias = expr_with_alias_and_order_by. expr ;
349
+ let sql_expr = expr_with_alias. expr ;
350
+ let alias = expr_with_alias. alias ;
351
+
352
+ // Convert SQL expression to DataFusion expression
353
+ let df_expr =
354
+ self . sql_to_expr ( sql_expr, plan. schema ( ) , planner_context) ?;
355
+
356
+ // Apply alias if present (though group by aliases are less common)
357
+ match alias {
358
+ Some ( alias_ident) => {
359
+ // If the expression is already an alias, replace the alias name
360
+ match df_expr {
361
+ Expr :: Alias ( alias_expr) => {
362
+ Ok ( alias_expr. expr . alias ( alias_ident. value ) )
363
+ }
364
+ _ => Ok ( df_expr. alias ( alias_ident. value ) ) ,
365
+ }
366
+ }
367
+ None => Ok ( df_expr) ,
368
+ }
369
+ } )
370
+ . collect :: < Result < Vec < _ > > > ( ) ?;
371
+
372
+ // Create the aggregate logical plan
373
+ LogicalPlanBuilder :: from ( plan)
374
+ . aggregate ( group_by_exprs, aggr_exprs) ?
375
+ . build ( )
376
+ }
377
+
299
378
/// Wrap the logical plan in a `SelectInto`
300
379
fn select_into (
301
380
& self ,
0 commit comments