Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion datafusion/core/tests/sql/unparser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ use datafusion_catalog::memory::MemorySchemaProvider;
use datafusion_catalog::{CatalogProvider, MemoryCatalogProvider, SchemaProvider};
use datafusion_common::Column;
use datafusion_expr::Expr;
use datafusion_sql::unparser::Unparser;
use datafusion_sql::unparser::dialect::{DefaultDialect, DuckDBDialect};
use datafusion_sql::unparser::{Unparser, plan_to_sql};
use itertools::Itertools;
use recursive::{set_minimum_stack_size, set_stack_allocation_size};

Expand Down Expand Up @@ -747,6 +747,31 @@ async fn optimized_duckdb_unparse_top_level_sort_over_agg_uses_select_alias() ->
Ok(())
}

#[tokio::test]
async fn optimized_filter_with_subquery_alias() -> Result<()> {
let ctx = SessionContext::new();
ctx.sql("create table t (a int)").await?.collect().await?;
let df = ctx
.sql(
"
select *
from (
select a
from t
) t2
where a = 1
",
)
.await?;
let plan = df.into_optimized_plan()?;
let sql = plan_to_sql(&plan)?.to_string();
assert_eq!(
sql,
"SELECT * FROM (SELECT t.a FROM t WHERE (t.a = 1)) AS t2"
);
Ok(())
}

/// The outcome of running a single roundtrip test.
///
/// A successful test produces [`TestCaseResult::Success`].
Expand Down
6 changes: 5 additions & 1 deletion datafusion/sql/src/unparser/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1632,7 +1632,11 @@ impl Unparser<'_> {
// we must emit a derived subquery: (SELECT ...) AS alias.
// Without this, the recursive handler would merge those clauses
// into the outer SELECT, losing the subquery structure entirely.
if unparsed_table_scan.is_none() && Self::requires_derived_subquery(plan)
// Also, do not add a table alias past a Filter, as otherwise the predicates might
// refer to invalid tables.
if (unparsed_table_scan.is_none()
&& Self::requires_derived_subquery(plan))
|| matches!(plan, LogicalPlan::Filter(_))
Comment on lines +1637 to +1639

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not add the Filter directly to requires_derived_subquery since technically the filter does not need it, but we can't also alias the table.

{
// When the dialect does not support column aliases in
// table aliases (e.g. SQLite), inject the aliases into
Expand Down
Loading