MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / plan_is_expr

Function plan_is_expr

src/sql/src/plan/query.rs:5686–5742  ·  view source on GitHub ↗
(
    ecx: &ExprContext,
    expr: &'a Expr<Aug>,
    construct: &IsExprConstruct<Aug>,
    not: bool,
)

Source from the content-addressed store, hash-verified

5684}
5685
5686fn 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

Callers 1

plan_expr_innerFunction · 0.85

Calls 10

plan_exprFunction · 0.85
type_as_anyMethod · 0.80
type_asMethod · 0.80
not_equalsMethod · 0.80
call_is_nullMethod · 0.45
call_unaryMethod · 0.45
cloneMethod · 0.45
as_refMethod · 0.45
andMethod · 0.45
notMethod · 0.45

Tested by

no test coverage detected