Skip to content

Commit 2ed8628

Browse files
committed
less code
1 parent 592c3ed commit 2ed8628

15 files changed

Lines changed: 91 additions & 290 deletions

File tree

datafusion/core/src/physical_planner.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3460,27 +3460,11 @@ mod tests {
34603460
ctx.sql(query).await?.create_physical_plan().await
34613461
}
34623462

3463-
async fn plan_sql_with_config(
3464-
query: &str,
3465-
config: SessionConfig,
3466-
) -> Result<Arc<dyn ExecutionPlan>> {
3467-
let ctx = SessionContext::new_with_config(config);
3468-
ctx.sql(query).await?.create_physical_plan().await
3469-
}
3470-
34713463
async fn collect_sql(query: &str) -> Result<Vec<RecordBatch>> {
34723464
let ctx = SessionContext::new();
34733465
ctx.sql(query).await?.collect().await
34743466
}
34753467

3476-
async fn collect_sql_with_config(
3477-
query: &str,
3478-
config: SessionConfig,
3479-
) -> Result<Vec<RecordBatch>> {
3480-
let ctx = SessionContext::new_with_config(config);
3481-
ctx.sql(query).await?.collect().await
3482-
}
3483-
34843468
#[tokio::test]
34853469
async fn test_all_operators() -> Result<()> {
34863470
let logical_plan = test_csv_scan()
@@ -3644,16 +3628,17 @@ mod tests {
36443628
let config = SessionConfig::new()
36453629
.with_target_partitions(4)
36463630
.set_bool("datafusion.optimizer.prefer_hash_join", false);
3631+
let ctx = SessionContext::new_with_config(config);
36473632

3648-
let plan = plan_sql_with_config(query, config.clone()).await?;
3633+
let plan = ctx.sql(query).await?.create_physical_plan().await?;
36493634
let formatted = displayable(plan.as_ref()).indent(true).to_string();
36503635
assert_contains!(
36513636
&formatted,
36523637
"HashJoinExec: mode=CollectLeft, join_type=LeftMark"
36533638
);
36543639
assert!(!formatted.contains("SortMergeJoinExec"), "{formatted}");
36553640

3656-
let batches = collect_sql_with_config(query, config).await?;
3641+
let batches = ctx.sql(query).await?.collect().await?;
36573642
assert_batches_eq!(
36583643
&[
36593644
"+-------+",

datafusion/expr/src/logical_plan/builder.rs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,7 +1154,7 @@ impl LogicalPlanBuilder {
11541154
.zip(right_keys)
11551155
.map(|(l, r)| (Expr::Column(l), Expr::Column(r)))
11561156
.collect();
1157-
let join_schema = build_join_schema_with_null_aware(
1157+
let join_schema = build_join_schema(
11581158
self.plan.schema(),
11591159
right.schema(),
11601160
&join_type,
@@ -1677,25 +1677,13 @@ fn mark_field(schema: &DFSchema, nullable: bool) -> (Option<TableReference>, Arc
16771677
/// Creates a schema for a join operation.
16781678
/// The fields from the left side are first.
16791679
///
1680-
/// The `mark` column of a mark join is non-nullable. Use
1681-
/// [`build_join_schema_with_null_aware`] for null-aware mark joins, whose mark
1682-
/// column can be `NULL` (SQL UNKNOWN).
1680+
/// When `null_aware` is set, the `LeftMark`/`RightMark` `mark` column is made
1681+
/// nullable so it can represent SQL UNKNOWN for null-aware `NOT IN` semantics.
1682+
/// `null_aware` has no effect on non-mark join types.
16831683
pub fn build_join_schema(
16841684
left: &DFSchema,
16851685
right: &DFSchema,
16861686
join_type: &JoinType,
1687-
) -> Result<DFSchema> {
1688-
build_join_schema_with_null_aware(left, right, join_type, false)
1689-
}
1690-
1691-
/// Like [`build_join_schema`], but makes the `LeftMark`/`RightMark` `mark`
1692-
/// column nullable when `null_aware` is set, so it can represent SQL UNKNOWN
1693-
/// for null-aware `NOT IN` semantics. `null_aware` has no effect on non-mark
1694-
/// join types.
1695-
pub fn build_join_schema_with_null_aware(
1696-
left: &DFSchema,
1697-
right: &DFSchema,
1698-
join_type: &JoinType,
16991687
null_aware: bool,
17001688
) -> Result<DFSchema> {
17011689
fn nullify_fields<'a>(
@@ -2933,13 +2921,13 @@ mod tests {
29332921
)?;
29342922

29352923
let join_schema =
2936-
build_join_schema(&left_schema, &right_schema, &JoinType::Left)?;
2924+
build_join_schema(&left_schema, &right_schema, &JoinType::Left, false)?;
29372925
assert_eq!(
29382926
join_schema.metadata(),
29392927
&HashMap::from([("key".to_string(), "left".to_string())])
29402928
);
29412929
let join_schema =
2942-
build_join_schema(&left_schema, &right_schema, &JoinType::Right)?;
2930+
build_join_schema(&left_schema, &right_schema, &JoinType::Right, false)?;
29432931
assert_eq!(
29442932
join_schema.metadata(),
29452933
&HashMap::from([("key".to_string(), "right".to_string())])

datafusion/expr/src/logical_plan/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub mod tree_node;
2828

2929
pub use builder::{
3030
LogicalPlanBuilder, LogicalPlanBuilderOptions, LogicalTableSource, UNNAMED_TABLE,
31-
build_join_schema, build_join_schema_with_null_aware, requalify_sides_if_needed,
31+
build_join_schema, requalify_sides_if_needed,
3232
table_scan, union, wrap_projection_for_join_if_necessary,
3333
};
3434
pub use ddl::{

datafusion/expr/src/logical_plan/plan.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use crate::utils::{
4747
use crate::{
4848
BinaryExpr, CreateMemoryTable, CreateView, Execute, Expr, ExprSchemable, GroupingSet,
4949
LogicalPlanBuilder, Operator, Prepare, TableProviderFilterPushDown, TableSource,
50-
WindowFunctionDefinition, build_join_schema_with_null_aware, expr_vec_fmt,
50+
WindowFunctionDefinition, build_join_schema, expr_vec_fmt,
5151
requalify_sides_if_needed,
5252
};
5353

@@ -668,7 +668,7 @@ impl LogicalPlan {
668668
null_equality,
669669
null_aware,
670670
}) => {
671-
let schema = build_join_schema_with_null_aware(
671+
let schema = build_join_schema(
672672
left.schema(),
673673
right.schema(),
674674
&join_type,
@@ -949,7 +949,7 @@ impl LogicalPlan {
949949
..
950950
}) => {
951951
let (left, right) = self.only_two_inputs(inputs)?;
952-
let schema = build_join_schema_with_null_aware(
952+
let schema = build_join_schema(
953953
left.schema(),
954954
right.schema(),
955955
join_type,
@@ -4279,7 +4279,7 @@ impl Join {
42794279
null_equality: NullEquality,
42804280
null_aware: bool,
42814281
) -> Result<Self> {
4282-
let join_schema = build_join_schema_with_null_aware(
4282+
let join_schema = build_join_schema(
42834283
left.schema(),
42844284
right.schema(),
42854285
&join_type,
@@ -4335,7 +4335,7 @@ impl Join {
43354335
.map(|(l, r)| (Expr::Column(l), Expr::Column(r)))
43364336
.collect();
43374337

4338-
let join_schema = build_join_schema_with_null_aware(
4338+
let join_schema = build_join_schema(
43394339
left_sch.schema(),
43404340
right_sch.schema(),
43414341
&original_join.join_type,

datafusion/optimizer/src/decorrelate_predicate_subquery.rs

Lines changed: 35 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -627,14 +627,6 @@ mod tests {
627627
))
628628
}
629629

630-
fn nullable_scalar_mark_scan(name: &str) -> Result<LogicalPlan> {
631-
let schema = Schema::new(vec![
632-
Field::new("id", DataType::Int32, true),
633-
Field::new("grp", DataType::Int32, true),
634-
]);
635-
table_scan(Some(name), &schema, None)?.build()
636-
}
637-
638630
fn has_left_mark_join_with_null_aware(
639631
plan: &LogicalPlan,
640632
expected_null_aware: bool,
@@ -1287,81 +1279,33 @@ mod tests {
12871279
)
12881280
}
12891281

1290-
#[test]
1291-
fn correlated_not_in_mark_join_is_null_aware_for_hashable_filter() -> Result<()> {
1292-
let outer_scan = nullable_scalar_mark_scan("outer_t")?;
1293-
let inner_scan = nullable_scalar_mark_scan("inner_t")?;
1294-
1295-
let subquery = Arc::new(
1296-
LogicalPlanBuilder::from(inner_scan)
1297-
.filter(
1298-
out_ref_col(DataType::Int32, "outer_t.grp").eq(col("inner_t.grp")),
1299-
)?
1300-
.project(vec![col("inner_t.id")])?
1301-
.build()?,
1302-
);
1303-
1304-
let plan = LogicalPlanBuilder::from(outer_scan)
1305-
.filter(not_in_subquery(col("outer_t.id"), subquery).is_null())?
1306-
.build()?;
1307-
1308-
let optimized = optimize_with_decorrelate(plan)?;
1309-
assert!(
1310-
has_left_mark_join_with_null_aware(&optimized, true),
1311-
"{}",
1312-
optimized.display_indent_schema()
1313-
);
1314-
1315-
Ok(())
1316-
}
1317-
1318-
#[test]
1319-
fn correlated_not_in_mark_join_is_not_null_aware_for_residual_filter() -> Result<()> {
1320-
let outer_scan = nullable_scalar_mark_scan("outer_t")?;
1321-
let inner_scan = nullable_scalar_mark_scan("inner_t")?;
1322-
1323-
let subquery = Arc::new(
1324-
LogicalPlanBuilder::from(inner_scan)
1325-
.filter(
1326-
out_ref_col(DataType::Int32, "outer_t.grp").lt(col("inner_t.grp")),
1327-
)?
1328-
.project(vec![col("inner_t.id")])?
1329-
.build()?,
1330-
);
1331-
1332-
let plan = LogicalPlanBuilder::from(outer_scan)
1333-
.filter(not_in_subquery(col("outer_t.id"), subquery).is_null())?
1334-
.build()?;
1335-
1336-
let optimized = optimize_with_decorrelate(plan)?;
1337-
assert!(
1338-
has_left_mark_join_with_null_aware(&optimized, false),
1339-
"{}",
1340-
optimized.display_indent_schema()
1341-
);
1342-
1343-
Ok(())
1344-
}
1345-
1346-
#[test]
1347-
fn correlated_not_in_mark_join_not_null_aware_for_non_nullable_value_key()
1348-
-> Result<()> {
1349-
// The value key `id` is non-nullable on both sides; only the
1350-
// correlation key `grp` is nullable. A NULL correlation key just makes
1351-
// the correlated subquery empty, so NOT IN can never be UNKNOWN and
1352-
// the mark join does not need null-aware semantics.
1282+
/// Builds `... WHERE (id NOT IN (SELECT id FROM inner WHERE <grp filter>))
1283+
/// IS NULL` over scans whose value key `id` has the given nullability (the
1284+
/// correlation key `grp` is always nullable), optimizes it, and asserts the
1285+
/// resulting `LeftMark` join's `null_aware` flag.
1286+
fn assert_correlated_not_in_mark_join_null_aware(
1287+
value_key_nullable: bool,
1288+
hashable_filter: bool,
1289+
expected_null_aware: bool,
1290+
) -> Result<()> {
13531291
let schema = Schema::new(vec![
1354-
Field::new("id", DataType::Int32, false),
1292+
Field::new("id", DataType::Int32, value_key_nullable),
13551293
Field::new("grp", DataType::Int32, true),
13561294
]);
13571295
let outer_scan = table_scan(Some("outer_t"), &schema, None)?.build()?;
13581296
let inner_scan = table_scan(Some("inner_t"), &schema, None)?.build()?;
13591297

1298+
let outer_grp = out_ref_col(DataType::Int32, "outer_t.grp");
1299+
let inner_grp = col("inner_t.grp");
1300+
let grp_filter = if hashable_filter {
1301+
outer_grp.eq(inner_grp)
1302+
} else {
1303+
outer_grp.lt(inner_grp)
1304+
};
1305+
13601306
let subquery = Arc::new(
13611307
LogicalPlanBuilder::from(inner_scan)
1362-
.filter(
1363-
out_ref_col(DataType::Int32, "outer_t.grp").eq(col("inner_t.grp")),
1364-
)?
1308+
.filter(grp_filter)?
13651309
.project(vec![col("inner_t.id")])?
13661310
.build()?,
13671311
);
@@ -1372,14 +1316,29 @@ mod tests {
13721316

13731317
let optimized = optimize_with_decorrelate(plan)?;
13741318
assert!(
1375-
has_left_mark_join_with_null_aware(&optimized, false),
1319+
has_left_mark_join_with_null_aware(&optimized, expected_null_aware),
13761320
"{}",
13771321
optimized.display_indent_schema()
13781322
);
13791323

13801324
Ok(())
13811325
}
13821326

1327+
#[test]
1328+
fn correlated_not_in_mark_join_null_awareness() -> Result<()> {
1329+
// Hashable (`=`) correlation filter on a nullable value key: NOT IN can
1330+
// be UNKNOWN, so the mark join is null-aware.
1331+
assert_correlated_not_in_mark_join_null_aware(true, true, true)?;
1332+
// Residual (`<`) correlation filter: the equijoin predicate can't be
1333+
// extracted, so the mark join is not null-aware.
1334+
assert_correlated_not_in_mark_join_null_aware(true, false, false)?;
1335+
// Non-nullable value key `id`: a NULL correlation key just makes the
1336+
// subquery empty, so NOT IN can never be UNKNOWN and the join is not
1337+
// null-aware.
1338+
assert_correlated_not_in_mark_join_null_aware(false, true, false)?;
1339+
Ok(())
1340+
}
1341+
13831342
#[test]
13841343
fn in_subquery_both_side_expr() -> Result<()> {
13851344
let table_scan = test_table_scan()?;

datafusion/optimizer/src/eliminate_cross_join.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ fn find_inner_join(
374374
left_input.schema(),
375375
right_input.schema(),
376376
&JoinType::Inner,
377+
false,
377378
)?);
378379

379380
return Ok(LogicalPlan::Join(Join {
@@ -397,6 +398,7 @@ fn find_inner_join(
397398
left_input.schema(),
398399
right.schema(),
399400
&JoinType::Inner,
401+
false,
400402
)?);
401403

402404
Ok(LogicalPlan::Join(Join {
@@ -1402,6 +1404,7 @@ mod tests {
14021404
t1.schema(),
14031405
t2.schema(),
14041406
&JoinType::Inner,
1407+
false,
14051408
)?);
14061409

14071410
let inner_join = LogicalPlan::Join(Join {

datafusion/optimizer/src/optimize_projections/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,7 +1024,8 @@ mod tests {
10241024
let left_schema = left_child.schema();
10251025
let right_schema = right_child.schema();
10261026
let schema = Arc::new(
1027-
build_join_schema(left_schema, right_schema, &JoinType::Inner).unwrap(),
1027+
build_join_schema(left_schema, right_schema, &JoinType::Inner, false)
1028+
.unwrap(),
10281029
);
10291030
Self {
10301031
exprs: vec![],

0 commit comments

Comments
 (0)