This is an automated email from the ASF dual-hosted git repository.

goldmedal pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new d68fca91fd Only unnest source for `EmptyRelation` (#15159)
d68fca91fd is described below

commit d68fca91fd4c73f2cd92d61d036bc0411a2ed826
Author: Dmitrii Blaginin <[email protected]>
AuthorDate: Mon Mar 24 11:15:28 2025 +0000

    Only unnest source for `EmptyRelation` (#15159)
    
    * Only unnest source for `EmptyRelation`
    
    * Add a note on new condition
    
    * Remove new test
    
    * Put all unnest assumptions into one function
---
 datafusion/sql/src/unparser/plan.rs       | 42 ++++++++++++++++++++++---------
 datafusion/sql/tests/cases/plan_to_sql.rs | 12 +++++++++
 2 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/datafusion/sql/src/unparser/plan.rs 
b/datafusion/sql/src/unparser/plan.rs
index eb99d1e270..a6d89638ff 100644
--- a/datafusion/sql/src/unparser/plan.rs
+++ b/datafusion/sql/src/unparser/plan.rs
@@ -378,8 +378,17 @@ impl Unparser<'_> {
                 };
                 if self.dialect.unnest_as_table_factor() && 
unnest_input_type.is_some() {
                     if let LogicalPlan::Unnest(unnest) = &p.input.as_ref() {
-                        return self
-                            .unnest_to_table_factor_sql(unnest, query, select, 
relation);
+                        if let Some(unnest_relation) =
+                            self.try_unnest_to_table_factor_sql(unnest)?
+                        {
+                            relation.unnest(unnest_relation);
+                            return self.select_to_sql_recursively(
+                                p.input.as_ref(),
+                                query,
+                                select,
+                                relation,
+                            );
+                        }
                     }
                 }
 
@@ -912,25 +921,34 @@ impl Unparser<'_> {
         None
     }
 
-    fn unnest_to_table_factor_sql(
+    fn try_unnest_to_table_factor_sql(
         &self,
         unnest: &Unnest,
-        query: &mut Option<QueryBuilder>,
-        select: &mut SelectBuilder,
-        relation: &mut RelationBuilder,
-    ) -> Result<()> {
+    ) -> Result<Option<UnnestRelationBuilder>> {
         let mut unnest_relation = UnnestRelationBuilder::default();
-        let LogicalPlan::Projection(p) = unnest.input.as_ref() else {
-            return internal_err!("Unnest input is not a Projection: 
{unnest:?}");
+        let LogicalPlan::Projection(projection) = unnest.input.as_ref() else {
+            return Ok(None);
         };
-        let exprs = p
+
+        if !matches!(projection.input.as_ref(), LogicalPlan::EmptyRelation(_)) 
{
+            // It may be possible that UNNEST is used as a source for the 
query.
+            // However, at this point, we don't yet know if it is just a 
single expression
+            // from another source or if it's from UNNEST.
+            //
+            // Unnest(Projection(EmptyRelation)) denotes a case with 
`UNNEST([...])`,
+            // which is normally safe to unnest as a table factor.
+            // However, in the future, more comprehensive checks can be added 
here.
+            return Ok(None);
+        };
+
+        let exprs = projection
             .expr
             .iter()
             .map(|e| self.expr_to_sql(e))
             .collect::<Result<Vec<_>>>()?;
         unnest_relation.array_exprs(exprs);
-        relation.unnest(unnest_relation);
-        self.select_to_sql_recursively(p.input.as_ref(), query, select, 
relation)
+
+        Ok(Some(unnest_relation))
     }
 
     fn is_scan_with_pushdown(scan: &TableScan) -> bool {
diff --git a/datafusion/sql/tests/cases/plan_to_sql.rs 
b/datafusion/sql/tests/cases/plan_to_sql.rs
index 0d0ab8808d..f9b1ac9249 100644
--- a/datafusion/sql/tests/cases/plan_to_sql.rs
+++ b/datafusion/sql/tests/cases/plan_to_sql.rs
@@ -636,6 +636,18 @@ fn roundtrip_statement_with_dialect() -> Result<()> {
             parser_dialect: Box::new(GenericDialect {}),
             unparser_dialect: 
Box::new(CustomDialectBuilder::default().with_unnest_as_table_factor(true).build()),
         },
+        TestStatementWithDialect {
+            sql: "SELECT unnest([1, 2, 3, 4]) from unnest([1, 2, 3]);",
+            expected: r#"SELECT UNNEST([1, 2, 3, 4]) AS 
UNNEST(make_array(Int64(1),Int64(2),Int64(3),Int64(4))) FROM UNNEST([1, 2, 
3])"#,
+            parser_dialect: Box::new(GenericDialect {}),
+            unparser_dialect: 
Box::new(CustomDialectBuilder::default().with_unnest_as_table_factor(true).build()),
+        },
+        TestStatementWithDialect {
+            sql: "SELECT unnest([1, 2, 3, 4]) from unnest([1, 2, 3]);",
+            expected: r#"SELECT UNNEST([1, 2, 3, 4]) AS 
UNNEST(make_array(Int64(1),Int64(2),Int64(3),Int64(4))) FROM UNNEST([1, 2, 
3])"#,
+            parser_dialect: Box::new(GenericDialect {}),
+            unparser_dialect: 
Box::new(CustomDialectBuilder::default().with_unnest_as_table_factor(true).build()),
+        },
         TestStatementWithDialect {
             sql: "SELECT * FROM unnest_table u, UNNEST(u.array_col)",
             expected: r#"SELECT u.array_col, u.struct_col, 
"UNNEST(outer_ref(u.array_col))" FROM unnest_table AS u CROSS JOIN LATERAL 
(SELECT UNNEST(u.array_col) AS "UNNEST(outer_ref(u.array_col))")"#,


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to