@@ -24,8 +24,8 @@ use crate::utils::{
24
24
resolve_columns, resolve_positions_to_exprs,
25
25
} ;
26
26
27
- use datafusion_common:: Column ;
28
27
use datafusion_common:: { not_impl_err, plan_err, DataFusionError , Result } ;
28
+ use datafusion_common:: { Column , UnnestOptions } ;
29
29
use datafusion_expr:: expr:: { Alias , Unnest } ;
30
30
use datafusion_expr:: expr_rewriter:: {
31
31
normalize_col, normalize_col_with_schemas_and_ambiguity_check,
@@ -282,30 +282,38 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
282
282
input : LogicalPlan ,
283
283
select_exprs : Vec < Expr > ,
284
284
) -> Result < LogicalPlan > {
285
- let mut exprs_to_unnest = vec ! [ ] ;
286
-
287
- for expr in select_exprs. iter ( ) {
288
- if let Expr :: Unnest ( Unnest { exprs } ) = expr {
289
- exprs_to_unnest. push ( exprs[ 0 ] . clone ( ) ) ;
290
- }
291
- }
285
+ let mut unnest_columns = vec ! [ ] ;
286
+ // Map unnest expressions to their argument
287
+ let projection_exprs = select_exprs
288
+ . into_iter ( )
289
+ . map ( |expr| {
290
+ if let Expr :: Unnest ( Unnest { ref exprs } ) = expr {
291
+ let column_name = expr. display_name ( ) ?;
292
+ unnest_columns. push ( column_name. clone ( ) ) ;
293
+ // Add alias for the argument expression, to avoid naming conflicts with other expressions
294
+ // in the select list. For example: `select unnest(col1), col1 from t`.
295
+ Ok ( exprs[ 0 ] . clone ( ) . alias ( column_name) )
296
+ } else {
297
+ Ok ( expr)
298
+ }
299
+ } )
300
+ . collect :: < Result < Vec < _ > > > ( ) ?;
292
301
293
302
// Do the final projection
294
- if exprs_to_unnest . is_empty ( ) {
303
+ if unnest_columns . is_empty ( ) {
295
304
LogicalPlanBuilder :: from ( input)
296
- . project ( select_exprs ) ?
305
+ . project ( projection_exprs ) ?
297
306
. build ( )
298
307
} else {
299
- if exprs_to_unnest . len ( ) > 1 {
308
+ if unnest_columns . len ( ) > 1 {
300
309
return not_impl_err ! ( "Only support single unnest expression for now" ) ;
301
310
}
302
-
303
- let expr = exprs_to_unnest[ 0 ] . clone ( ) ;
304
- let column = expr. display_name ( ) ?;
305
-
311
+ let unnest_column = unnest_columns. pop ( ) . unwrap ( ) ;
312
+ // Set preserve_nulls to false to ensure compatibility with DuckDB and PostgreSQL
313
+ let unnest_options = UnnestOptions :: new ( ) . with_preserve_nulls ( false ) ;
306
314
LogicalPlanBuilder :: from ( input)
307
- . project ( vec ! [ expr ] ) ?
308
- . unnest_column ( column ) ?
315
+ . project ( projection_exprs ) ?
316
+ . unnest_column_with_options ( unnest_column , unnest_options ) ?
309
317
. build ( )
310
318
}
311
319
}
0 commit comments