(
&self,
plan: LogicalPlan,
_config: &dyn OptimizerConfig,
)
| 62 | } |
| 63 | |
| 64 | fn rewrite( |
| 65 | &self, |
| 66 | plan: LogicalPlan, |
| 67 | _config: &dyn OptimizerConfig, |
| 68 | ) -> Result<Transformed<LogicalPlan>> { |
| 69 | match plan { |
| 70 | LogicalPlan::Join(Join { |
| 71 | left, |
| 72 | right, |
| 73 | mut on, |
| 74 | filter: Some(expr), |
| 75 | join_type, |
| 76 | join_constraint, |
| 77 | schema, |
| 78 | null_equality, |
| 79 | null_aware, |
| 80 | }) => { |
| 81 | let left_schema = left.schema(); |
| 82 | let right_schema = right.schema(); |
| 83 | let (equijoin_predicates, non_equijoin_expr) = |
| 84 | split_eq_and_noneq_join_predicate(expr, left_schema, right_schema)?; |
| 85 | |
| 86 | // Equi-join operators like HashJoin support a special behavior |
| 87 | // that evaluates `NULL = NULL` as true instead of NULL. Therefore, |
| 88 | // we transform `t1.c1 IS NOT DISTINCT FROM t2.c1` into an equi-join |
| 89 | // and set the `NullEquality` configuration in the join operator. |
| 90 | // This allows certain queries to use Hash Join instead of |
| 91 | // Nested Loop Join, resulting in better performance. |
| 92 | // |
| 93 | // Only convert when there are NO equijoin predicates, to be conservative. |
| 94 | if on.is_empty() |
| 95 | && equijoin_predicates.is_empty() |
| 96 | && non_equijoin_expr.is_some() |
| 97 | { |
| 98 | // SAFETY: checked in the outer `if` |
| 99 | let expr = non_equijoin_expr.clone().unwrap(); |
| 100 | let (equijoin_predicates, non_equijoin_expr) = |
| 101 | split_is_not_distinct_from_and_other_join_predicate( |
| 102 | expr, |
| 103 | left_schema, |
| 104 | right_schema, |
| 105 | )?; |
| 106 | |
| 107 | if !equijoin_predicates.is_empty() { |
| 108 | on.extend(equijoin_predicates); |
| 109 | |
| 110 | return Ok(Transformed::yes(LogicalPlan::Join(Join { |
| 111 | left, |
| 112 | right, |
| 113 | on, |
| 114 | filter: non_equijoin_expr, |
| 115 | join_type, |
| 116 | join_constraint, |
| 117 | schema, |
| 118 | // According to `is not distinct from`'s semantics, it's |
| 119 | // safe to override it |
| 120 | null_equality: NullEquality::NullEqualsNull, |
| 121 | null_aware, |
nothing calls this directly
no test coverage detected