You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/08/09 02:12:50 UTC
(datafusion) 01/01: fix: support untyped NULL input for median (#24104)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-24104-6b6cc0939ef599235e0356402492b4ab2c738e55
in repository https://gitbox.apache.org/repos/asf/datafusion.git
commit cc61491adde99acc59f334c48398ae4ea0f8d3fd
Author: Ma Zhengxuan <49...@users.noreply.github.com>
AuthorDate: Sun Aug 9 10:12:26 2026 +0800
fix: support untyped NULL input for median (#24104)
## Which issue does this PR close?
- Closes #24077.
## Rationale for this change
`median(NULL)` worked in DataFusion 53 but regressed in DataFusion 54.
The untyped NULL argument remained `DataType::Null`, causing physical
planning to create a median accumulator for an unsupported input type.
## What changes are included in this PR?
- Keep the existing declarative signature for `median`.
- Handle `DataType::Null` in physical execution using `NoopAccumulator`.
- Use a Null state field for Null input.
- Fall back to the generic groups accumulator adapter for Null input.
- Add a SQL logic regression test for `median(NULL)`.
## Are these changes tested?
Yes.
- `cargo fmt --all -- --check`
- `cargo test --profile=ci --test sqllogictests -- aggregate.slt`
- `cargo test -p datafusion-functions-aggregate`
- `cargo clippy -p datafusion-functions-aggregate --all-targets
--all-features -- -D warnings`
## Are there any user-facing changes?
Yes. `median(NULL)` now returns NULL with `DataType::Null` instead of
failing during physical execution.
---------
Co-authored-by: mazhengxuan <ma...@didiglobal.com>
---
datafusion/functions-aggregate/src/median.rs | 18 +++++++++++++++++-
datafusion/sqllogictest/test_files/aggregate.slt | 5 +++++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/datafusion/functions-aggregate/src/median.rs b/datafusion/functions-aggregate/src/median.rs
index 81a3c076df..fb74da87c7 100644
--- a/datafusion/functions-aggregate/src/median.rs
+++ b/datafusion/functions-aggregate/src/median.rs
@@ -53,6 +53,7 @@ use datafusion_expr::{
use datafusion_expr::{EmitTo, GroupsAccumulator};
use datafusion_functions_aggregate_common::aggregate::groups_accumulator::accumulate::accumulate;
use datafusion_functions_aggregate_common::aggregate::groups_accumulator::nulls::filtered_null_mask;
+use datafusion_functions_aggregate_common::noop_accumulator::NoopAccumulator;
use datafusion_functions_aggregate_common::utils::{GenericDistinctBuffer, Hashable};
use datafusion_macros::user_doc;
use std::collections::HashMap;
@@ -138,6 +139,17 @@ impl AggregateUDFImpl for Median {
}
fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
+ if args.input_fields[0].data_type().is_null() {
+ return Ok(vec![
+ Field::new(
+ format_state_name(args.name, self.name()),
+ DataType::Null,
+ true,
+ )
+ .into(),
+ ]);
+ }
+
//Intermediate state is a list of the elements we have collected so far
let field = Field::new_list_field(args.input_fields[0].data_type().clone(), true);
let state_name = if args.is_distinct {
@@ -174,6 +186,10 @@ impl AggregateUDFImpl for Median {
}
let dt = acc_args.expr_fields[0].data_type().clone();
+ if dt.is_null() {
+ return Ok(Box::new(NoopAccumulator::default()));
+ }
+
downcast_integer! {
dt => (helper, dt),
DataType::Float16 => helper!(Float16Type, dt),
@@ -192,7 +208,7 @@ impl AggregateUDFImpl for Median {
}
fn groups_accumulator_supported(&self, args: AccumulatorArgs) -> bool {
- !args.is_distinct
+ !args.is_distinct && !args.expr_fields[0].data_type().is_null()
}
fn create_groups_accumulator(
diff --git a/datafusion/sqllogictest/test_files/aggregate.slt b/datafusion/sqllogictest/test_files/aggregate.slt
index 26b8a78f39..1a3e3f5aa6 100644
--- a/datafusion/sqllogictest/test_files/aggregate.slt
+++ b/datafusion/sqllogictest/test_files/aggregate.slt
@@ -1200,6 +1200,11 @@ select approx_median(NULL), arrow_typeof(approx_median(NULL)) from median_table;
----
NULL Null
+query ?T
+select median(NULL), arrow_typeof(median(NULL));
+----
+NULL Null
+
# median decimal
statement ok
create table t(c decimal(10, 4)) as values (0.0001), (0.0002), (0.0003), (0.0004), (0.0005), (0.0006);
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org