1#include "duckdb/optimizer/rule/case_simplification.hpp"
2
3#include "duckdb/execution/expression_executor.hpp"
4#include "duckdb/planner/expression/bound_case_expression.hpp"
5
6namespace duckdb {
7
8CaseSimplificationRule::CaseSimplificationRule(ExpressionRewriter &rewriter) : Rule(rewriter) {
9 // match on a CaseExpression that has a ConstantExpression as a check
10 auto op = make_uniq<CaseExpressionMatcher>();
11 root = std::move(op);
12}
13
14unique_ptr<Expression> CaseSimplificationRule::Apply(LogicalOperator &op, vector<reference<Expression>> &bindings,
15 bool &changes_made, bool is_root) {
16 auto &root = bindings[0].get().Cast<BoundCaseExpression>();
17 for (idx_t i = 0; i < root.case_checks.size(); i++) {
18 auto &case_check = root.case_checks[i];
19 if (case_check.when_expr->IsFoldable()) {
20 // the WHEN check is a foldable expression
21 // use an ExpressionExecutor to execute the expression
22 auto constant_value = ExpressionExecutor::EvaluateScalar(context&: GetContext(), expr: *case_check.when_expr);
23
24 // fold based on the constant condition
25 auto condition = constant_value.DefaultCastAs(target_type: LogicalType::BOOLEAN);
26 if (condition.IsNull() || !BooleanValue::Get(value: condition)) {
27 // the condition is always false: remove this case check
28 root.case_checks.erase(position: root.case_checks.begin() + i);
29 i--;
30 } else {
31 // the condition is always true
32 // move the THEN clause to the ELSE of the case
33 root.else_expr = std::move(case_check.then_expr);
34 // remove this case check and any case checks after this one
35 root.case_checks.erase(first: root.case_checks.begin() + i, last: root.case_checks.end());
36 break;
37 }
38 }
39 }
40 if (root.case_checks.empty()) {
41 // no case checks left: return the ELSE expression
42 return std::move(root.else_expr);
43 }
44 return nullptr;
45}
46
47} // namespace duckdb
48