Skip to content

Commit f509d21

Browse files
authored
Merge branch 'apache:main' into fix-15428-map-distinct-tests
2 parents aac87fb + 3e058f0 commit f509d21

80 files changed

Lines changed: 5293 additions & 1174 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

datafusion-examples/examples/udf/advanced_udaf.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ use datafusion::{arrow::datatypes::DataType, logical_expr::Volatility};
2323
use std::sync::Arc;
2424

2525
use arrow::array::{
26-
ArrayRef, AsArray, Float32Array, PrimitiveArray, PrimitiveBuilder, UInt32Array,
26+
Array, ArrayRef, AsArray, BooleanArray, Float32Array, PrimitiveArray,
27+
PrimitiveBuilder, UInt32Array,
2728
};
29+
use arrow::buffer::NullBuffer;
2830
use arrow::datatypes::{ArrowNativeTypeOp, ArrowPrimitiveType, Float64Type, UInt32Type};
2931
use arrow::record_batch::RecordBatch;
3032
use arrow_schema::FieldRef;
@@ -237,7 +239,7 @@ impl GroupsAccumulator for GeometricMeanGroupsAccumulator {
237239
&mut self,
238240
values: &[ArrayRef],
239241
group_indices: &[usize],
240-
opt_filter: Option<&arrow::array::BooleanArray>,
242+
opt_filter: Option<&BooleanArray>,
241243
total_num_groups: usize,
242244
) -> Result<()> {
243245
assert_eq!(values.len(), 1, "single argument to update_batch");
@@ -359,6 +361,43 @@ impl GroupsAccumulator for GeometricMeanGroupsAccumulator {
359361
])
360362
}
361363

364+
fn convert_to_state(
365+
&self,
366+
values: &[ArrayRef],
367+
opt_filter: Option<&BooleanArray>,
368+
) -> Result<Vec<ArrayRef>> {
369+
assert_eq!(values.len(), 1, "single argument to convert_to_state");
370+
371+
let prods = values[0]
372+
.as_primitive::<Float64Type>()
373+
.clone()
374+
.with_data_type(self.prod_data_type.clone());
375+
let counts = UInt32Array::from_value(1, prods.len());
376+
377+
let filter_nulls = opt_filter.map(|filter| {
378+
let validity = match filter.nulls() {
379+
Some(nulls) => filter.values() & nulls.inner(),
380+
None => filter.values().clone(),
381+
};
382+
NullBuffer::new(validity)
383+
});
384+
let nulls = NullBuffer::union(filter_nulls.as_ref(), prods.nulls());
385+
386+
let prods =
387+
PrimitiveArray::<Float64Type>::new(prods.values().clone(), nulls.clone())
388+
.with_data_type(self.prod_data_type.clone());
389+
let counts = UInt32Array::new(counts.values().clone(), nulls);
390+
391+
Ok(vec![
392+
Arc::new(prods) as ArrayRef,
393+
Arc::new(counts) as ArrayRef,
394+
])
395+
}
396+
397+
fn supports_convert_to_state(&self) -> bool {
398+
true
399+
}
400+
362401
fn size(&self) -> usize {
363402
self.counts.capacity() * size_of::<u32>()
364403
+ self.prods.capacity() * size_of::<Float64Type>()

datafusion/common-runtime/src/join_set.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ use std::task::{Context, Poll};
2121
use tokio::runtime::Handle;
2222
use tokio::task::{AbortHandle, Id, JoinError, LocalSet};
2323

24-
/// A wrapper around Tokio's JoinSet that forwards all API calls while optionally
24+
/// A wrapper around [Tokio's `JoinSet`] that forwards all API calls while optionally
2525
/// instrumenting spawned tasks and blocking closures with custom tracing behavior.
26-
/// If no tracer is injected via `trace_utils::set_tracer`, tasks and closures are executed
26+
/// If no tracer is injected via [`set_join_set_tracer`], tasks and closures are executed
2727
/// without any instrumentation.
28+
///
29+
/// [Tokio's `JoinSet`]: tokio::task::JoinSet
30+
/// [`set_join_set_tracer`]: crate::trace_utils::set_join_set_tracer
2831
#[derive(Debug)]
2932
pub struct JoinSet<T> {
3033
inner: tokio::task::JoinSet<T>,

datafusion/core/tests/physical_optimizer/enforce_distribution.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,12 @@ impl ExecutionPlan for SinglePartitionMaintainsOrderExec {
265265
vec![&self.input]
266266
}
267267

268-
fn required_input_distribution(&self) -> Vec<Distribution> {
269-
vec![Distribution::SinglePartition]
268+
fn input_distribution_requirements(
269+
&self,
270+
) -> datafusion_physical_plan::InputDistributionRequirements {
271+
datafusion_physical_plan::InputDistributionRequirements::new(vec![
272+
Distribution::SinglePartition,
273+
])
270274
}
271275

272276
fn maintains_input_order(&self) -> Vec<bool> {
@@ -823,6 +827,49 @@ fn range_grouping_set_aggregate_rehashes_with_grouping_id() -> Result<()> {
823827
Ok(())
824828
}
825829

830+
#[test]
831+
fn range_inner_hash_join_rehashes_incompatible_range_partitioning() -> Result<()> {
832+
let left = parquet_exec_with_output_partitioning(range_partitioning(
833+
"a",
834+
[10, 20, 30],
835+
SortOptions::default(),
836+
)?);
837+
let right = projection_exec_with_alias(
838+
parquet_exec_with_output_partitioning(range_partitioning(
839+
"a",
840+
[10, 30, 40],
841+
SortOptions::default(),
842+
)?),
843+
vec![
844+
("a".to_string(), "a1".to_string()),
845+
("b".to_string(), "b1".to_string()),
846+
],
847+
);
848+
let join_on = vec![(
849+
Arc::new(Column::new_with_schema("a", &left.schema())?) as _,
850+
Arc::new(Column::new_with_schema("a1", &right.schema())?) as _,
851+
)];
852+
let join = hash_join_exec(left, right, &join_on, &JoinType::Inner);
853+
854+
let plan = TestConfig::default()
855+
.with_query_execution_partitions(4)
856+
.to_plan(join, &DISTRIB_DISTRIB_SORT);
857+
858+
assert_plan!(
859+
plan,
860+
@r"
861+
HashJoinExec: mode=Partitioned, join_type=Inner, on=[(a@0, a1@0)]
862+
RepartitionExec: partitioning=Hash([a@0], 4), input_partitions=4
863+
DataSourceExec: file_groups={4 groups: [[p0], [p1], [p2], [p3]]}, projection=[a, b, c, d, e], output_partitioning=Range([a@0 ASC], [(10), (20), (30)], 4), file_type=parquet
864+
RepartitionExec: partitioning=Hash([a1@0], 4), input_partitions=4
865+
ProjectionExec: expr=[a@0 as a1, b@1 as b1]
866+
DataSourceExec: file_groups={4 groups: [[p0], [p1], [p2], [p3]]}, projection=[a, b, c, d, e], output_partitioning=Range([a@0 ASC], [(10), (30), (40)], 4), file_type=parquet
867+
"
868+
);
869+
870+
Ok(())
871+
}
872+
826873
#[test]
827874
fn multi_hash_joins() -> Result<()> {
828875
let left = parquet_exec();

datafusion/core/tests/physical_optimizer/ensure_requirements.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -974,8 +974,12 @@ impl ExecutionPlan for MockReqExec {
974974
fn children(&self) -> Vec<&Arc<dyn ExecutionPlan>> {
975975
vec![&self.input]
976976
}
977-
fn required_input_distribution(&self) -> Vec<Distribution> {
978-
vec![self.dist.clone()]
977+
fn input_distribution_requirements(
978+
&self,
979+
) -> datafusion_physical_plan::InputDistributionRequirements {
980+
datafusion_physical_plan::InputDistributionRequirements::new(vec![
981+
self.dist.clone(),
982+
])
979983
}
980984
fn required_input_ordering(&self) -> Vec<Option<OrderingRequirements>> {
981985
vec![

datafusion/core/tests/physical_optimizer/projection_pushdown.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,9 @@ fn test_output_req_after_projection() -> Result<()> {
800800
if let Distribution::KeyPartitioned(vec) = after_optimize
801801
.downcast_ref::<OutputRequirementExec>()
802802
.unwrap()
803-
.required_input_distribution()[0]
803+
.input_distribution_requirements()
804+
.child_distribution(0)
805+
.unwrap()
804806
.clone()
805807
{
806808
assert!(

datafusion/core/tests/physical_optimizer/sanity_checker.rs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ use insta::assert_snapshot;
1919
use std::sync::Arc;
2020

2121
use crate::physical_optimizer::test_utils::{
22-
bounded_window_exec, global_limit_exec, local_limit_exec, memory_exec,
23-
projection_exec, repartition_exec, sort_exec, sort_expr, sort_expr_options,
24-
sort_merge_join_exec, sort_preserving_merge_exec, union_exec,
22+
bounded_window_exec, global_limit_exec, hash_join_exec, local_limit_exec,
23+
memory_exec, projection_exec, repartition_exec, sort_exec, sort_expr,
24+
sort_expr_options, sort_merge_join_exec, sort_preserving_merge_exec, union_exec,
2525
};
2626

2727
use arrow::compute::SortOptions;
@@ -30,8 +30,8 @@ use datafusion::datasource::stream::{FileStreamProvider, StreamConfig, StreamTab
3030
use datafusion::prelude::{CsvReadOptions, SessionContext};
3131
use datafusion_common::config::ConfigOptions;
3232
use datafusion_common::{JoinType, Result, ScalarValue};
33-
use datafusion_physical_expr::Partitioning;
3433
use datafusion_physical_expr::expressions::{Literal, col};
34+
use datafusion_physical_expr::{Partitioning, RangePartitioning, SplitPoint};
3535
use datafusion_physical_expr_common::sort_expr::LexOrdering;
3636
use datafusion_physical_optimizer::PhysicalOptimizerRule;
3737
use datafusion_physical_optimizer::sanity_checker::SanityCheckPlan;
@@ -400,6 +400,49 @@ fn assert_sanity_check(plan: &Arc<dyn ExecutionPlan>, is_sane: bool) {
400400
);
401401
}
402402

403+
fn range_partitioned_exec(
404+
schema: &SchemaRef,
405+
key: &str,
406+
split_points: impl IntoIterator<Item = i32>,
407+
) -> Result<Arc<dyn ExecutionPlan>> {
408+
let split_points = split_points
409+
.into_iter()
410+
.map(|value| SplitPoint::new(vec![ScalarValue::Int32(Some(value))]))
411+
.collect();
412+
let partitioning = Partitioning::Range(RangePartitioning::try_new(
413+
[sort_expr(key, schema)].into(),
414+
split_points,
415+
)?);
416+
RepartitionExec::try_new(memory_exec(schema), partitioning)
417+
.map(|exec| Arc::new(exec) as Arc<dyn ExecutionPlan>)
418+
}
419+
420+
#[test]
421+
fn test_partitioned_hash_join_requires_co_partitioned_children() -> Result<()> {
422+
let schema = create_test_schema2();
423+
let join_on = vec![(col("a", &schema)?, col("a", &schema)?)];
424+
425+
let compatible_join = hash_join_exec(
426+
range_partitioned_exec(&schema, "a", [10])?,
427+
range_partitioned_exec(&schema, "a", [10])?,
428+
join_on.clone(),
429+
None,
430+
&JoinType::Inner,
431+
)?;
432+
assert_sanity_check(&compatible_join, true);
433+
434+
let incompatible_join = hash_join_exec(
435+
range_partitioned_exec(&schema, "a", [10])?,
436+
range_partitioned_exec(&schema, "a", [20])?,
437+
join_on,
438+
None,
439+
&JoinType::Inner,
440+
)?;
441+
assert_sanity_check(&incompatible_join, false);
442+
443+
Ok(())
444+
}
445+
403446
#[tokio::test]
404447
/// Tests that plan is valid when the sort requirements are satisfied.
405448
async fn test_bounded_window_agg_sort_requirement() -> Result<()> {

datafusion/core/tests/user_defined/user_defined_aggregates.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,22 @@ impl GroupsAccumulator for TestGroupsAccumulator {
877877
Ok(())
878878
}
879879

880+
fn convert_to_state(
881+
&self,
882+
values: &[ArrayRef],
883+
_opt_filter: Option<&arrow::array::BooleanArray>,
884+
) -> Result<Vec<ArrayRef>> {
885+
let len = values.first().map_or(0, |value| value.len());
886+
Ok(vec![
887+
Arc::new(PrimitiveArray::<UInt64Type>::from_value(self.result, len))
888+
as ArrayRef,
889+
])
890+
}
891+
892+
fn supports_convert_to_state(&self) -> bool {
893+
true
894+
}
895+
880896
fn size(&self) -> usize {
881897
size_of::<u64>()
882898
}

datafusion/core/tests/user_defined/user_defined_plan.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -708,8 +708,12 @@ impl ExecutionPlan for TopKExec {
708708
&self.cache
709709
}
710710

711-
fn required_input_distribution(&self) -> Vec<Distribution> {
712-
vec![Distribution::SinglePartition]
711+
fn input_distribution_requirements(
712+
&self,
713+
) -> datafusion_physical_plan::InputDistributionRequirements {
714+
datafusion_physical_plan::InputDistributionRequirements::new(vec![
715+
Distribution::SinglePartition,
716+
])
713717
}
714718

715719
fn children(&self) -> Vec<&Arc<dyn ExecutionPlan>> {

0 commit comments

Comments
 (0)