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
42 changes: 22 additions & 20 deletions datafusion/functions-aggregate/src/median.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ use arrow::datatypes::{
};

use datafusion_common::hash_utils::RandomState;
use datafusion_common::types::{NativeType, logical_float64};
use datafusion_common::utils::take_function_args;
use datafusion_common::{
DataFusionError, Result, ScalarValue, assert_eq_or_internal_err, exec_datafusion_err,
internal_datafusion_err, internal_err,
exec_err, internal_datafusion_err, internal_err,
};
use datafusion_expr::function::StateFieldsArgs;
use datafusion_expr::{
Accumulator, AggregateUDFImpl, Coercion, Documentation, Signature, TypeSignature,
TypeSignatureClass, Volatility, function::AccumulatorArgs, utils::format_state_name,
Accumulator, AggregateUDFImpl, Documentation, Signature, Volatility,
function::AccumulatorArgs, utils::format_state_name,
};
use datafusion_expr::{EmitTo, GroupsAccumulator};
use datafusion_functions_aggregate_common::aggregate::groups_accumulator::accumulate::accumulate;
Expand Down Expand Up @@ -104,22 +104,7 @@ impl Median {
// Integer inputs are coerced to Float64 so the average of the two
// middle values is not truncated. This matches DuckDB / PostgreSQL / Spark.
// Float and Decimal inputs preserve their type.
signature: Signature::one_of(
vec![
TypeSignature::Coercible(vec![Coercion::new_exact(
TypeSignatureClass::Decimal,
)]),
TypeSignature::Coercible(vec![Coercion::new_exact(
TypeSignatureClass::Float,
)]),
TypeSignature::Coercible(vec![Coercion::new_implicit(
TypeSignatureClass::Native(logical_float64()),
vec![TypeSignatureClass::Integer],
NativeType::Float64,
)]),
],
Volatility::Immutable,
),
signature: Signature::user_defined(Volatility::Immutable),
}
}
}
Expand All @@ -133,6 +118,23 @@ impl AggregateUDFImpl for Median {
&self.signature
}

fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
let [data_type] = take_function_args(self.name(), arg_types)?;

fn coerced_type(data_type: &DataType) -> Result<DataType> {
match data_type {
DataType::Dictionary(_, value_type) => coerced_type(value_type),
// Untyped NULL defaults to Float64, matching Signature::numeric.
DataType::Null => Ok(DataType::Float64),
data_type if data_type.is_integer() => Ok(DataType::Float64),
data_type if data_type.is_numeric() => Ok(data_type.clone()),
_ => exec_err!("Median not supported for {data_type}"),
}
}

Ok(vec![coerced_type(data_type)?])
}

fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
Ok(arg_types[0].clone())
}
Expand Down
5 changes: 5 additions & 0 deletions datafusion/sqllogictest/test_files/aggregate.slt
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,11 @@ select approx_median(NULL), arrow_typeof(approx_median(NULL)) from median_table;
----
NULL Null

query RT
select median(NULL), arrow_typeof(median(NULL));
----
NULL Float64

# 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);
Expand Down