1#include "duckdb/optimizer/rule/date_part_simplification.hpp"
2
3#include "duckdb/common/exception.hpp"
4#include "duckdb/planner/expression/bound_constant_expression.hpp"
5#include "duckdb/planner/expression/bound_function_expression.hpp"
6#include "duckdb/optimizer/matcher/expression_matcher.hpp"
7#include "duckdb/optimizer/expression_rewriter.hpp"
8#include "duckdb/common/enums/date_part_specifier.hpp"
9#include "duckdb/function/function.hpp"
10#include "duckdb/function/function_binder.hpp"
11
12namespace duckdb {
13
14DatePartSimplificationRule::DatePartSimplificationRule(ExpressionRewriter &rewriter) : Rule(rewriter) {
15 auto func = make_uniq<FunctionExpressionMatcher>();
16 func->function = make_uniq<SpecificFunctionMatcher>(args: "date_part");
17 func->matchers.push_back(x: make_uniq<ConstantExpressionMatcher>());
18 func->matchers.push_back(x: make_uniq<ExpressionMatcher>());
19 func->policy = SetMatcher::Policy::ORDERED;
20 root = std::move(func);
21}
22
23unique_ptr<Expression> DatePartSimplificationRule::Apply(LogicalOperator &op, vector<reference<Expression>> &bindings,
24 bool &changes_made, bool is_root) {
25 auto &date_part = bindings[0].get().Cast<BoundFunctionExpression>();
26 auto &constant_expr = bindings[1].get().Cast<BoundConstantExpression>();
27 auto &constant = constant_expr.value;
28
29 if (constant.IsNull()) {
30 // NULL specifier: return constant NULL
31 return make_uniq<BoundConstantExpression>(args: Value(date_part.return_type));
32 }
33 // otherwise check the specifier
34 auto specifier = GetDatePartSpecifier(specifier: StringValue::Get(value: constant));
35 string new_function_name;
36 switch (specifier) {
37 case DatePartSpecifier::YEAR:
38 new_function_name = "year";
39 break;
40 case DatePartSpecifier::MONTH:
41 new_function_name = "month";
42 break;
43 case DatePartSpecifier::DAY:
44 new_function_name = "day";
45 break;
46 case DatePartSpecifier::DECADE:
47 new_function_name = "decade";
48 break;
49 case DatePartSpecifier::CENTURY:
50 new_function_name = "century";
51 break;
52 case DatePartSpecifier::MILLENNIUM:
53 new_function_name = "millennium";
54 break;
55 case DatePartSpecifier::QUARTER:
56 new_function_name = "quarter";
57 break;
58 case DatePartSpecifier::WEEK:
59 new_function_name = "week";
60 break;
61 case DatePartSpecifier::YEARWEEK:
62 new_function_name = "yearweek";
63 break;
64 case DatePartSpecifier::DOW:
65 new_function_name = "dayofweek";
66 break;
67 case DatePartSpecifier::ISODOW:
68 new_function_name = "isodow";
69 break;
70 case DatePartSpecifier::DOY:
71 new_function_name = "dayofyear";
72 break;
73 case DatePartSpecifier::EPOCH:
74 new_function_name = "epoch";
75 break;
76 case DatePartSpecifier::MICROSECONDS:
77 new_function_name = "microsecond";
78 break;
79 case DatePartSpecifier::MILLISECONDS:
80 new_function_name = "millisecond";
81 break;
82 case DatePartSpecifier::SECOND:
83 new_function_name = "second";
84 break;
85 case DatePartSpecifier::MINUTE:
86 new_function_name = "minute";
87 break;
88 case DatePartSpecifier::HOUR:
89 new_function_name = "hour";
90 break;
91 default:
92 return nullptr;
93 }
94 // found a replacement function: bind it
95 vector<unique_ptr<Expression>> children;
96 children.push_back(x: std::move(date_part.children[1]));
97
98 string error;
99 FunctionBinder binder(rewriter.context);
100 auto function = binder.BindScalarFunction(DEFAULT_SCHEMA, name: new_function_name, children: std::move(children), error, is_operator: false);
101 if (!function) {
102 throw BinderException(error);
103 }
104 return function;
105}
106
107} // namespace duckdb
108