(constraint: &ast::JoinConstraint)
| 53 | type JoinConstraintResult = (Vec<(String, String)>, Option<SqlExpr>); |
| 54 | |
| 55 | fn extract_join_constraint(constraint: &ast::JoinConstraint) -> Result<JoinConstraintResult> { |
| 56 | match constraint { |
| 57 | ast::JoinConstraint::On(expr) => { |
| 58 | let mut keys = Vec::new(); |
| 59 | let mut non_equi = Vec::new(); |
| 60 | extract_equi_keys(expr, &mut keys, &mut non_equi)?; |
| 61 | let cond = if non_equi.is_empty() { |
| 62 | None |
| 63 | } else { |
| 64 | let mut combined = convert_expr(&non_equi[0])?; |
| 65 | for pred in &non_equi[1..] { |
| 66 | combined = SqlExpr::BinaryOp { |
| 67 | left: Box::new(combined), |
| 68 | op: crate::types::BinaryOp::And, |
| 69 | right: Box::new(convert_expr(pred)?), |
| 70 | }; |
| 71 | } |
| 72 | Some(combined) |
| 73 | }; |
| 74 | Ok((keys, cond)) |
| 75 | } |
| 76 | ast::JoinConstraint::Using(columns) => { |
| 77 | let keys = columns |
| 78 | .iter() |
| 79 | .map(|c| { |
| 80 | let name = crate::parser::normalize::normalize_object_name_checked(c)?; |
| 81 | Ok((name.clone(), name)) |
| 82 | }) |
| 83 | .collect::<Result<Vec<_>>>()?; |
| 84 | Ok((keys, None)) |
| 85 | } |
| 86 | ast::JoinConstraint::Natural => Err(SqlError::Unsupported { |
| 87 | detail: "NATURAL JOIN is not supported; use explicit ON or USING clause".into(), |
| 88 | }), |
| 89 | ast::JoinConstraint::None => Err(SqlError::Unsupported { |
| 90 | detail: "implicit cross join (no ON/USING clause) is not supported".into(), |
| 91 | }), |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | fn extract_equi_keys( |
| 96 | expr: &ast::Expr, |
no test coverage detected