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
11using namespace duckdb;
12using namespace std;
13
14DatePartSimplificationRule::DatePartSimplificationRule(ExpressionRewriter &rewriter) : Rule(rewriter) {
15 auto func = make_unique<FunctionExpressionMatcher>();
16 func->function = make_unique<SpecificFunctionMatcher>("date_part");
17 func->matchers.push_back(make_unique<ConstantExpressionMatcher>());
18 func->matchers.push_back(make_unique<ExpressionMatcher>());
19 func->policy = SetMatcher::Policy::ORDERED;
20 root = move(func);
21}
22
23unique_ptr<Expression> DatePartSimplificationRule::Apply(LogicalOperator &op, vector<Expression *> &bindings,
24 bool &changes_made) {
25 auto &date_part = (BoundFunctionExpression &)*bindings[0];
26 auto &constant_expr = (BoundConstantExpression &)*bindings[1];
27 auto &constant = constant_expr.value;
28
29 if (constant.is_null) {
30 // NULL specifier: return constant NULL
31 return make_unique<BoundConstantExpression>(Value(date_part.return_type));
32 }
33 // otherwise check the specifier
34 auto specifier = GetDatePartSpecifier(constant.str_value);
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 = "millenium";
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::DOW:
62 new_function_name = "dayofweek";
63 break;
64 case DatePartSpecifier::ISODOW:
65 new_function_name = "isodow";
66 break;
67 case DatePartSpecifier::DOY:
68 new_function_name = "dayofyear";
69 break;
70 case DatePartSpecifier::EPOCH:
71 new_function_name = "epoch";
72 break;
73 case DatePartSpecifier::MICROSECONDS:
74 new_function_name = "microsecond";
75 break;
76 case DatePartSpecifier::MILLISECONDS:
77 new_function_name = "millisecond";
78 break;
79 case DatePartSpecifier::SECOND:
80 new_function_name = "second";
81 break;
82 case DatePartSpecifier::MINUTE:
83 new_function_name = "minute";
84 break;
85 case DatePartSpecifier::HOUR:
86 new_function_name = "hour";
87 break;
88 default:
89 return nullptr;
90 }
91 // found a replacement function: bind it
92 vector<SQLType> arguments{date_part.function.arguments[1]};
93 vector<unique_ptr<Expression>> children;
94 children.push_back(move(date_part.children[1]));
95
96 return ScalarFunction::BindScalarFunction(rewriter.context, DEFAULT_SCHEMA, new_function_name, arguments,
97 move(children), false);
98}
99