Recursively walk the WHERE expression, extracting subquery predicates. Returns `None` if the entire expression was consumed (subquery-only), or `Some(expr)` with the remaining non-subquery predicates.
(
expr: &Expr,
joins: &mut Vec<SubqueryJoin>,
catalog: &dyn SqlCatalog,
functions: &FunctionRegistry,
temporal: crate::TemporalScope,
)
| 65 | /// Returns `None` if the entire expression was consumed (subquery-only), |
| 66 | /// or `Some(expr)` with the remaining non-subquery predicates. |
| 67 | fn extract_recursive( |
| 68 | expr: &Expr, |
| 69 | joins: &mut Vec<SubqueryJoin>, |
| 70 | catalog: &dyn SqlCatalog, |
| 71 | functions: &FunctionRegistry, |
| 72 | temporal: crate::TemporalScope, |
| 73 | ) -> Result<Option<Expr>> { |
| 74 | match expr { |
| 75 | // AND: recurse both sides, reconstruct with remaining parts. |
| 76 | Expr::BinaryOp { |
| 77 | left, |
| 78 | op: ast::BinaryOperator::And, |
| 79 | right, |
| 80 | } => { |
| 81 | let left_remaining = extract_recursive(left, joins, catalog, functions, temporal)?; |
| 82 | let right_remaining = extract_recursive(right, joins, catalog, functions, temporal)?; |
| 83 | match (left_remaining, right_remaining) { |
| 84 | (None, None) => Ok(None), |
| 85 | (Some(l), None) => Ok(Some(l)), |
| 86 | (None, Some(r)) => Ok(Some(r)), |
| 87 | (Some(l), Some(r)) => Ok(Some(Expr::BinaryOp { |
| 88 | left: Box::new(l), |
| 89 | op: ast::BinaryOperator::And, |
| 90 | right: Box::new(r), |
| 91 | })), |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | // IN (SELECT ...): rewrite as semi-join. |
| 96 | Expr::InSubquery { |
| 97 | expr: outer_expr, |
| 98 | subquery, |
| 99 | negated, |
| 100 | } => { |
| 101 | if let Some(join) = |
| 102 | try_plan_in_subquery(outer_expr, subquery, *negated, catalog, functions, temporal)? |
| 103 | { |
| 104 | joins.push(join); |
| 105 | Ok(None) // This predicate is consumed. |
| 106 | } else { |
| 107 | // Cannot plan as join — return original expression. |
| 108 | Ok(Some(expr.clone())) |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // Scalar subquery comparison: `col > (SELECT AGG(...) FROM ...)` |
| 113 | Expr::BinaryOp { left, op, right } if is_comparison_op(op) => { |
| 114 | if let Expr::Subquery(subquery) = right.as_ref() { |
| 115 | if let Some(scalar) = |
| 116 | try_plan_scalar_subquery(subquery, catalog, functions, temporal)? |
| 117 | { |
| 118 | joins.push(scalar.join); |
| 119 | Ok(Some(Expr::BinaryOp { |
| 120 | left: left.clone(), |
| 121 | op: op.clone(), |
| 122 | right: Box::new(scalar.replacement_expr), |
| 123 | })) |
| 124 | } else { |
no test coverage detected