(
ecx: &ExprContext,
expr: &'a Expr<Aug>,
construct: &IsExprConstruct<Aug>,
not: bool,
)
| 5684 | } |
| 5685 | |
| 5686 | fn plan_is_expr<'a>( |
| 5687 | ecx: &ExprContext, |
| 5688 | expr: &'a Expr<Aug>, |
| 5689 | construct: &IsExprConstruct<Aug>, |
| 5690 | not: bool, |
| 5691 | ) -> Result<HirScalarExpr, PlanError> { |
| 5692 | let expr_hir = plan_expr(ecx, expr)?; |
| 5693 | |
| 5694 | let mut result = match construct { |
| 5695 | IsExprConstruct::Null => { |
| 5696 | // PostgreSQL can plan `NULL IS NULL` but not `$1 IS NULL`. This is |
| 5697 | // at odds with our type coercion rules, which treat `NULL` literals |
| 5698 | // and unconstrained parameters identically. Providing a type hint |
| 5699 | // of string means we wind up supporting both. |
| 5700 | expr_hir.type_as_any(ecx)?.call_is_null() |
| 5701 | } |
| 5702 | IsExprConstruct::Unknown => expr_hir.type_as(ecx, &SqlScalarType::Bool)?.call_is_null(), |
| 5703 | IsExprConstruct::True => expr_hir |
| 5704 | .type_as(ecx, &SqlScalarType::Bool)? |
| 5705 | .call_unary(UnaryFunc::IsTrue(expr_func::IsTrue)), |
| 5706 | IsExprConstruct::False => expr_hir |
| 5707 | .type_as(ecx, &SqlScalarType::Bool)? |
| 5708 | .call_unary(UnaryFunc::IsFalse(expr_func::IsFalse)), |
| 5709 | IsExprConstruct::DistinctFrom(expr2) => { |
| 5710 | // There are three cases: |
| 5711 | // 1. Both terms are non-null, in which case the result should be `a != b`. |
| 5712 | // 2. Exactly one term is null, in which case the result should be true. |
| 5713 | // 3. Both terms are null, in which case the result should be false. |
| 5714 | // |
| 5715 | // (a != b OR a IS NULL OR b IS NULL) AND (a IS NOT NULL OR b IS NOT NULL) |
| 5716 | |
| 5717 | // We'll need `expr != expr2`, but don't just construct this HIR directly. Instead, |
| 5718 | // construct an AST expression for `expr != expr2` and plan it to get proper type |
| 5719 | // checking, implicit casts, etc. (This seems to be also what Postgres does.) |
| 5720 | let ne_ast = expr.clone().not_equals(expr2.as_ref().clone()); |
| 5721 | let ne_hir = plan_expr(ecx, &ne_ast)?.type_as_any(ecx)?; |
| 5722 | |
| 5723 | let expr1_hir = expr_hir.type_as_any(ecx)?; |
| 5724 | let expr2_hir = plan_expr(ecx, expr2)?.type_as_any(ecx)?; |
| 5725 | |
| 5726 | let term1 = HirScalarExpr::variadic_or(vec![ |
| 5727 | ne_hir, |
| 5728 | expr1_hir.clone().call_is_null(), |
| 5729 | expr2_hir.clone().call_is_null(), |
| 5730 | ]); |
| 5731 | let term2 = HirScalarExpr::variadic_or(vec![ |
| 5732 | expr1_hir.call_is_null().not(), |
| 5733 | expr2_hir.call_is_null().not(), |
| 5734 | ]); |
| 5735 | term1.and(term2) |
| 5736 | } |
| 5737 | }; |
| 5738 | if not { |
| 5739 | result = result.not(); |
| 5740 | } |
| 5741 | Ok(result) |
| 5742 | } |
| 5743 |
no test coverage detected