Skip to main content

compile_match_expr

Function compile_match_expr 

Source
pub fn compile_match_expr(
    ctx: &SessionContext,
    match_expr: &str,
) -> Result<Arc<dyn PhysicalExpr>, DataFusionError>
Expand description

Parses, validates, and plans match_expr into an Arc<dyn PhysicalExpr> – the whole evaluator, correct by construction because DataFusion does the parsing and the evaluation.

  1. Parse with ctx.parse_sql_expr, against match_schema. ctx is expected to be a bare SessionContext::new() (no lakehouse tables or catalog registered) – see QueryDenyList’s doc comment for why the same bare context is used both at refresh and from deny_queries.
  2. Validate with exactly two checks: the result type is Boolean, and at least one column is referenced. An unknown column or function already fails at step 1; a subquery, aggregate, or window function cannot be lowered to a scalar PhysicalExpr and fails at step 3 – each with DataFusion’s own diagnostic.
  3. Plan the validated Expr into a PhysicalExpr with the free-function datafusion::physical_expr::create_physical_expr – deliberately not SessionContext::create_physical_expr/SessionState::create_physical_expr, both of which run the expression through ExprSimplifier::coerce first and would silently insert a CAST for a type-mismatched comparison (client = 42 becomes CAST(client AS Int64) = 42, which compiles, then either errors on every real value or – worse – happens to parse and quietly matches something the admin never intended). The free function’s own doc comment is explicit that it performs no coercion (“There should be no coercion during physical planning”) – but it also performs no operand-type checking at this stage: binary() happily builds a BinaryExpr node comparing a Utf8 column against an Int64/Timestamp literal, and Arrow’s comparison kernels are the ones that actually refuse it, only once the node is evaluated. Left there, that would be exactly the “silent per-query failure” this design wants to avoid – so step 4 forces that evaluation now.
  4. Canary-evaluate the compiled expression once against QueryAttribution::probe, a fixed one-row batch that exists for no other reason. Every match-context column is Utf8, so the only way this can fail is the type mismatch step 3 doesn’t catch; catching it here turns “never fires” into a loud compile-time error, at the one-time cost of a single evaluate() call per rule (refresh/deny_queries time, never per query).