1#include "duckdb/optimizer/rule/constant_folding.hpp"
2
3#include "duckdb/common/exception.hpp"
4#include "duckdb/execution/expression_executor.hpp"
5#include "duckdb/optimizer/expression_rewriter.hpp"
6#include "duckdb/planner/expression/bound_constant_expression.hpp"
7
8namespace duckdb {
9
10//! The ConstantFoldingExpressionMatcher matches on any scalar expression (i.e. Expression::IsFoldable is true)
11class ConstantFoldingExpressionMatcher : public FoldableConstantMatcher {
12public:
13 bool Match(Expression &expr, vector<reference<Expression>> &bindings) override {
14 // we also do not match on ConstantExpressions, because we cannot fold those any further
15 if (expr.type == ExpressionType::VALUE_CONSTANT) {
16 return false;
17 }
18 return FoldableConstantMatcher::Match(expr, bindings);
19 }
20};
21
22ConstantFoldingRule::ConstantFoldingRule(ExpressionRewriter &rewriter) : Rule(rewriter) {
23 auto op = make_uniq<ConstantFoldingExpressionMatcher>();
24 root = std::move(op);
25}
26
27unique_ptr<Expression> ConstantFoldingRule::Apply(LogicalOperator &op, vector<reference<Expression>> &bindings,
28 bool &changes_made, bool is_root) {
29 auto &root = bindings[0].get();
30 // the root is a scalar expression that we have to fold
31 D_ASSERT(root.IsFoldable() && root.type != ExpressionType::VALUE_CONSTANT);
32
33 // use an ExpressionExecutor to execute the expression
34 Value result_value;
35 if (!ExpressionExecutor::TryEvaluateScalar(context&: GetContext(), expr: root, result&: result_value)) {
36 return nullptr;
37 }
38 D_ASSERT(result_value.type().InternalType() == root.return_type.InternalType());
39 // now get the value from the result vector and insert it back into the plan as a constant expression
40 return make_uniq<BoundConstantExpression>(args&: result_value);
41}
42
43} // namespace duckdb
44