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]