Visitar URL original
Unparser emits empty SELECT list for empty Projection nodes, ignoring supports_empty_select_list · Issue #27332 · apache/datafusion · GitHub
Skip to content

Unparser emits empty SELECT list for empty Projection nodes, ignoring supports_empty_select_list #27332

Open

Description

@dreverri

Describe the bug

Unparsing the optimized plan of a simple count(*) query with a filter produces SELECT FROM ... (an empty select list), even for dialects whose supports_empty_select_list() is false. Engines that don't accept an empty select list reject the generated SQL. For example, BigQuery fails with:

SELECT list must not be empty

The column used in the filter isn't needed above the Filter, so optimize_projections prunes it and leaves a Projection with no expressions:

Projection: count(Int64(1)) AS count(*)
  Aggregate: groupBy=[[]], aggr=[[count(Int64(1))]]
    Projection:
      Filter: t.id > Int32(10)
        TableScan: t projection=[id]

#19221 (closing #18991) added Dialect::supports_empty_select_list and a SELECT 1 fallback, but only the TableScan path checks it (the case where the scan has projection=[], as in select count(*) from t with no filter). An empty Projection node goes through reconstruct_select_statement, which uses p.expr as is.

To Reproduce

use datafusion::prelude::SessionContext;
use datafusion::sql::unparser::plan_to_sql;

let ctx = SessionContext::new();
ctx.sql("create table t (id int)").await?.collect().await?;
let plan = ctx
    .sql("select count(*) from t where id > 10")
    .await?
    .into_optimized_plan()?;
println!("{}", plan_to_sql(&plan)?);

Output (default dialect):

SELECT count(1) AS "count(*)" FROM (SELECT FROM t WHERE (t.id > 10))

BigQueryDialect produces the same thing with backtick quoting.

Expected behavior

An empty Projection should get the same dialect-dependent fallback as an empty TableScan projection:

  • Dialects with supports_empty_select_list() == false (default, BigQuery, ...):
    SELECT count(1) AS "count(*)" FROM (SELECT 1 FROM t WHERE (t.id > 10))
  • Dialects that support it (PostgreSQL): unchanged, SELECT FROM ...

Additional context

The fix is small: in reconstruct_select_statement (datafusion/sql/src/unparser/plan.rs), use self.empty_projection_fallback() when p.expr is empty. I'll open a PR with the fix and tests.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions