diff --git a/src/frontend/src/binder/expr/mod.rs b/src/frontend/src/binder/expr/mod.rs index 0bc12545984ca..b1bd37b168010 100644 --- a/src/frontend/src/binder/expr/mod.rs +++ b/src/frontend/src/binder/expr/mod.rs @@ -471,6 +471,60 @@ impl Binder { Ok(func_call.into()) } + /// The optimization check for the following case-when expression pattern + /// e.g., select case 1 when (...) then (...) else (...) end; + fn check_constant_case_when_optimization( + &mut self, + conditions: Vec, + results_expr: Vec, + operand: Option>, + fallback: Option, + constant_case_when_eval_inputs: &mut Vec, + ) -> bool { + // The operand value to be compared later + let operand_value; + + if let Some(operand) = operand { + let Ok(operand) = self.bind_expr_inner(*operand) else { + return false; + }; + if !operand.is_const() { + return false; + } + operand_value = operand; + } else { + return false; + } + + for (condition, result) in zip_eq_fast(conditions, results_expr) { + if let Expr::Value(_) = condition.clone() { + let Ok(res) = self.bind_expr_inner(condition.clone()) else { + return false; + }; + // Found a match + if res == operand_value { + constant_case_when_eval_inputs.push(result); + return true; + } + } else { + return false; + } + } + + // Otherwise this will eventually go through fallback arm + debug_assert!( + constant_case_when_eval_inputs.is_empty(), + "expect `inputs` to be empty" + ); + + let Some(fallback) = fallback else { + return false; + }; + + constant_case_when_eval_inputs.push(fallback); + true + } + /// The helper function to check if the current case-when /// expression in `bind_case` could be optimized /// into `ConstantLookupExpression` @@ -493,6 +547,12 @@ impl Binder { let Ok(operand) = self.bind_expr_inner(*operand) else { return false; }; + // This optimization should be done in subsequent optimization phase + // if the operand is const + // e.g., select case 1 when 1 then 114514 else 1919810 end; + if operand.is_const() { + return false; + } constant_lookup_inputs.push(operand); } else { return false; @@ -506,7 +566,7 @@ impl Binder { constant_lookup_inputs.push(input); } else { // If at least one condition is not in the simple form / not constant, - // we can NOT do the subsequent optimization then + // we can NOT do the subsequent optimization pass return false; } @@ -538,6 +598,27 @@ impl Binder { .transpose()?; let mut constant_lookup_inputs = Vec::new(); + let mut constant_case_when_eval_inputs = Vec::new(); + + let constant_case_when_flag = self.check_constant_case_when_optimization( + conditions.clone(), + results_expr.clone(), + operand.clone(), + else_result_expr.clone(), + &mut constant_case_when_eval_inputs, + ); + + if constant_case_when_flag { + // Sanity check + if constant_case_when_eval_inputs.len() != 1 { + return Err(ErrorCode::BindError( + "expect `constant_case_when_eval_inputs` only contains a single bound expression".to_string() + ) + .into()); + } + // Directly return the first element of the vector + return Ok(constant_case_when_eval_inputs[0].take()); + } // See if the case-when expression can be optimized let optimize_flag = self.check_bind_case_optimization(