diff --git a/datafusion/src/execution/context.rs b/datafusion/src/execution/context.rs index 926e2db9450a..165263084cc7 100644 --- a/datafusion/src/execution/context.rs +++ b/datafusion/src/execution/context.rs @@ -893,7 +893,7 @@ mod tests { logical_plan::{col, create_udf, sum, Expr}, }; use crate::{ - datasource::{MemTable, TableType}, + datasource::{empty::EmptyTable, MemTable, TableType}, logical_plan::create_udaf, physical_plan::expressions::AvgAccumulator, }; @@ -3333,6 +3333,19 @@ mod tests { assert_batches_sorted_eq!(expected, &result); } + #[tokio::test] + async fn query_empty_table() { + let mut ctx = ExecutionContext::new(); + let empty_table = Arc::new(EmptyTable::new(Arc::new(Schema::empty()))); + ctx.register_table("test_tbl", empty_table).unwrap(); + let sql = "SELECT * FROM test_tbl"; + let result = plan_and_collect(&mut ctx, sql) + .await + .expect("Query empty table"); + let expected = vec!["++", "++"]; + assert_batches_sorted_eq!(expected, &result); + } + struct MyPhysicalPlanner {} impl PhysicalPlanner for MyPhysicalPlanner { diff --git a/datafusion/src/optimizer/projection_push_down.rs b/datafusion/src/optimizer/projection_push_down.rs index 2544d89d0492..a9e571f3d00b 100644 --- a/datafusion/src/optimizer/projection_push_down.rs +++ b/datafusion/src/optimizer/projection_push_down.rs @@ -83,9 +83,10 @@ fn get_projected_schema( .collect(); if projection.is_empty() { - if has_projection { + if has_projection && !schema.fields().is_empty() { // Ensure that we are reading at least one column from the table in case the query - // does not reference any columns directly such as "SELECT COUNT(1) FROM table" + // does not reference any columns directly such as "SELECT COUNT(1) FROM table", + // except when the table is empty (no column) projection.push(0); } else { // for table scan without projection, we default to return all columns