{"record":{"id":"32c426ab0a8f6154","repo":"risingwavelabs/risingwave","slug":"expect-when-expression-to-be-const","errorCode":null,"errorMessage":"expect when expression to be const","messagePattern":"expect when expression to be const","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/scalar/case.rs","lineNumber":281,"sourceCode":"fn build_constant_lookup_expr(\n    return_type: DataType,\n    children: Vec<BoxedExpression>,\n) -> Result<BoxedExpression> {\n    if children.is_empty() {\n        bail!(\"children expression must not be empty for constant lookup expression\");\n    }\n\n    let mut children = children;\n\n    let operand = children.remove(0);\n\n    let mut arms = HashMap::new();\n\n    // Build the `arms` with iterating over `when` & `then` clauses\n    let mut iter = children.into_iter().array_chunks();\n    for [when, then] in iter.by_ref() {\n        let Ok(Some(s)) = when.eval_const() else {\n            bail!(\"expect when expression to be const\");\n        };\n        arms.insert(s, then);\n    }\n\n    let fallback = if let Some(else_clause) = iter.into_remainder().next() {\n        if else_clause.return_type() != return_type {\n            bail!(\"Type mismatched between else and case.\");\n        }\n        Some(else_clause)\n    } else {\n        None\n    };\n\n    let BoxedExpression::Sync(operand) = operand else {\n        return Ok(ConstantLookupExpression::new(return_type, arms, fallback, operand).boxed());\n    };\n    let arms: Vec<_> = arms.into_iter().collect();\n    let sync_arms: HashMap<ScalarImpl, Arc<dyn SyncExpression>> = match try_convert_all(","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/scalar/case.rs#L263-L299","documentation":"The constant-lookup optimization requires each WHEN key to be a constant that can be evaluated at build time so it can be stored in a HashMap. If `eval_const` on a WHEN expression fails or returns NULL, the builder cannot build the lookup table and bails.","triggerScenarios":"`build_constant_lookup_expr` receiving a WHEN expression that is not a literal/stable constant (e.g. a column reference, non-deterministic function) or evaluates to NULL, usually from a planner rule that misjudged const-ness.","commonSituations":"CASE with non-literal WHEN conditions reaching this builder; planner version differences changing which CASEs are routed to constant lookup.","solutions":["Ensure WHEN keys are literal constants in the query.","Check whether the planner incorrectly converted a general CASE to constant_lookup; report/fix the frontend rule.","Use the general `build_case_expr` path instead for non-constant WHEN conditions."],"exampleFix":"// before (non-const WHEN key)\nCASE x WHEN some_column THEN 'a' ELSE 'b' END\n// after\nCASE x WHEN 1 THEN 'a' WHEN 2 THEN 'b' ELSE 'b' END","handlingStrategy":"validation","validationCode":"// ensure WHEN is constant before routing to constant lookup\nlet is_const = matches!(when_expr, Expr::Literal(_) | Expr::InputRef(_)) && when_expr.eval_const().is_ok();\nif !is_const { /* use general case builder */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only route CASEs with literal WHEN keys to constant lookup.","Check eval_const returns Some (not NULL) for each key.","Keep WHEN keys deterministic and literal in SQL."],"tags":["rust","expression-builder","const-evaluation","case-expression"],"backgroundTag":"invalid-argument-value","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}