From 3722229edd77d563e2411e570c68096075430d89 Mon Sep 17 00:00:00 2001 From: Anton Karpenko Date: Thu, 20 Aug 2026 12:05:46 +0300 Subject: [PATCH] fix: return EmptyExec for LIMIT 0 in physical planning Short-circuit physical planning when a limit requests zero rows by returning an EmptyExec with the input schema. --- datafusion/core/src/physical_planner.rs | 30 +++++++++++++++---------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/datafusion/core/src/physical_planner.rs b/datafusion/core/src/physical_planner.rs index 29eeef9e305e4..a18dcbdc2d2a8 100644 --- a/datafusion/core/src/physical_planner.rs +++ b/datafusion/core/src/physical_planner.rs @@ -1238,20 +1238,26 @@ impl DefaultPhysicalPlanner { ); }; - // GlobalLimitExec requires a single partition for input - let input = if input.output_partitioning().partition_count() == 1 { - input - } else { - // Apply a LocalLimitExec to each partition. The optimizer will also insert - // a CoalescePartitionsExec between the GlobalLimitExec and LocalLimitExec - if let Some(fetch) = fetch { - Arc::new(LocalLimitExec::new(input, fetch + skip)) - } else { - input + match fetch { + Some(0) => { + // Return an empty exec node if the number of requested rows is 0 + Arc::new(EmptyExec::new(input.schema())) } - }; + Some(fetch) => { + // GlobalLimitExec requires a single partition for input + let input = if input.output_partitioning().partition_count() == 1 + { + input + } else { + // Apply a LocalLimitExec to each partition. The optimizer will also insert + // a CoalescePartitionsExec between the GlobalLimitExec and LocalLimitExec + Arc::new(LocalLimitExec::new(input, fetch + skip)) + }; - Arc::new(GlobalLimitExec::new(input, skip, fetch)) + Arc::new(GlobalLimitExec::new(input, skip, Some(fetch))) + } + None => Arc::new(GlobalLimitExec::new(input, skip, None)), + } } LogicalPlan::Unnest(Unnest { list_type_columns,