datafusion_optimizer/
eliminate_join.rs1use crate::optimizer::ApplyOrder;
20use crate::{OptimizerConfig, OptimizerRule};
21use datafusion_common::tree_node::Transformed;
22use datafusion_common::{Result, ScalarValue};
23use datafusion_expr::JoinType::Inner;
24use datafusion_expr::{
25 logical_plan::{EmptyRelation, LogicalPlan},
26 Expr,
27};
28
29#[derive(Default, Debug)]
32pub struct EliminateJoin;
33
34impl EliminateJoin {
35 pub fn new() -> Self {
36 Self {}
37 }
38}
39
40impl OptimizerRule for EliminateJoin {
41 fn name(&self) -> &str {
42 "eliminate_join"
43 }
44
45 fn apply_order(&self) -> Option<ApplyOrder> {
46 Some(ApplyOrder::TopDown)
47 }
48
49 fn rewrite(
50 &self,
51 plan: LogicalPlan,
52 _config: &dyn OptimizerConfig,
53 ) -> Result<Transformed<LogicalPlan>> {
54 match plan {
55 LogicalPlan::Join(join) if join.join_type == Inner && join.on.is_empty() => {
56 match join.filter {
57 Some(Expr::Literal(ScalarValue::Boolean(Some(false)), _)) => Ok(
58 Transformed::yes(LogicalPlan::EmptyRelation(EmptyRelation {
59 produce_one_row: false,
60 schema: join.schema,
61 })),
62 ),
63 _ => Ok(Transformed::no(LogicalPlan::Join(join))),
64 }
65 }
66 _ => Ok(Transformed::no(plan)),
67 }
68 }
69
70 fn supports_rewrite(&self) -> bool {
71 true
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use crate::assert_optimized_plan_eq_snapshot;
78 use crate::eliminate_join::EliminateJoin;
79 use crate::OptimizerContext;
80 use datafusion_common::Result;
81 use datafusion_expr::JoinType::Inner;
82 use datafusion_expr::{lit, logical_plan::builder::LogicalPlanBuilder};
83 use std::sync::Arc;
84
85 macro_rules! assert_optimized_plan_equal {
86 (
87 $plan:expr,
88 @ $expected:literal $(,)?
89 ) => {{
90 let optimizer_ctx = OptimizerContext::new().with_max_passes(1);
91 let rules: Vec<Arc<dyn crate::OptimizerRule + Send + Sync>> = vec![Arc::new(EliminateJoin::new())];
92 assert_optimized_plan_eq_snapshot!(
93 optimizer_ctx,
94 rules,
95 $plan,
96 @ $expected,
97 )
98 }};
99 }
100
101 #[test]
102 fn join_on_false() -> Result<()> {
103 let plan = LogicalPlanBuilder::empty(false)
104 .join_on(
105 LogicalPlanBuilder::empty(false).build()?,
106 Inner,
107 Some(lit(false)),
108 )?
109 .build()?;
110
111 assert_optimized_plan_equal!(plan, @"EmptyRelation: rows=0")
112 }
113}