1 | #include "duckdb/parser/expression/cast_expression.hpp" |
---|---|
2 | #include "duckdb/parser/expression/constant_expression.hpp" |
3 | #include "duckdb/parser/expression/function_expression.hpp" |
4 | #include "duckdb/parser/transformer.hpp" |
5 | #include "duckdb/common/operator/cast_operators.hpp" |
6 | |
7 | namespace duckdb { |
8 | |
9 | unique_ptr<ParsedExpression> Transformer::TransformInterval(duckdb_libpgquery::PGIntervalConstant &node) { |
10 | // handle post-fix notation of INTERVAL |
11 | |
12 | // three scenarios |
13 | // interval (expr) year |
14 | // interval 'string' year |
15 | // interval int year |
16 | unique_ptr<ParsedExpression> expr; |
17 | switch (node.val_type) { |
18 | case duckdb_libpgquery::T_PGAExpr: |
19 | expr = TransformExpression(node: node.eval); |
20 | break; |
21 | case duckdb_libpgquery::T_PGString: |
22 | expr = make_uniq<ConstantExpression>(args: Value(node.sval)); |
23 | break; |
24 | case duckdb_libpgquery::T_PGInteger: |
25 | expr = make_uniq<ConstantExpression>(args: Value(node.ival)); |
26 | break; |
27 | default: |
28 | throw InternalException("Unsupported interval transformation"); |
29 | } |
30 | |
31 | if (!node.typmods) { |
32 | return make_uniq<CastExpression>(args: LogicalType::INTERVAL, args: std::move(expr)); |
33 | } |
34 | |
35 | int32_t mask = PGPointerCast<duckdb_libpgquery::PGAConst>(ptr: node.typmods->head->data.ptr_value)->val.val.ival; |
36 | // these seemingly random constants are from datetime.hpp |
37 | // they are copied here to avoid having to include this header |
38 | // the bitshift is from the function INTERVAL_MASK in the parser |
39 | constexpr int32_t MONTH_MASK = 1 << 1; |
40 | constexpr int32_t YEAR_MASK = 1 << 2; |
41 | constexpr int32_t DAY_MASK = 1 << 3; |
42 | constexpr int32_t HOUR_MASK = 1 << 10; |
43 | constexpr int32_t MINUTE_MASK = 1 << 11; |
44 | constexpr int32_t SECOND_MASK = 1 << 12; |
45 | constexpr int32_t MILLISECOND_MASK = 1 << 13; |
46 | constexpr int32_t MICROSECOND_MASK = 1 << 14; |
47 | |
48 | // we need to check certain combinations |
49 | // because certain interval masks (e.g. INTERVAL '10' HOURS TO DAYS) set multiple bits |
50 | // for now we don't support all of the combined ones |
51 | // (we might add support if someone complains about it) |
52 | |
53 | string fname; |
54 | LogicalType target_type; |
55 | if (mask & YEAR_MASK && mask & MONTH_MASK) { |
56 | // DAY TO HOUR |
57 | throw ParserException("YEAR TO MONTH is not supported"); |
58 | } else if (mask & DAY_MASK && mask & HOUR_MASK) { |
59 | // DAY TO HOUR |
60 | throw ParserException("DAY TO HOUR is not supported"); |
61 | } else if (mask & DAY_MASK && mask & MINUTE_MASK) { |
62 | // DAY TO MINUTE |
63 | throw ParserException("DAY TO MINUTE is not supported"); |
64 | } else if (mask & DAY_MASK && mask & SECOND_MASK) { |
65 | // DAY TO SECOND |
66 | throw ParserException("DAY TO SECOND is not supported"); |
67 | } else if (mask & HOUR_MASK && mask & MINUTE_MASK) { |
68 | // DAY TO SECOND |
69 | throw ParserException("HOUR TO MINUTE is not supported"); |
70 | } else if (mask & HOUR_MASK && mask & SECOND_MASK) { |
71 | // DAY TO SECOND |
72 | throw ParserException("HOUR TO SECOND is not supported"); |
73 | } else if (mask & MINUTE_MASK && mask & SECOND_MASK) { |
74 | // DAY TO SECOND |
75 | throw ParserException("MINUTE TO SECOND is not supported"); |
76 | } else if (mask & YEAR_MASK) { |
77 | // YEAR |
78 | fname = "to_years"; |
79 | target_type = LogicalType::INTEGER; |
80 | } else if (mask & MONTH_MASK) { |
81 | // MONTH |
82 | fname = "to_months"; |
83 | target_type = LogicalType::INTEGER; |
84 | } else if (mask & DAY_MASK) { |
85 | // DAY |
86 | fname = "to_days"; |
87 | target_type = LogicalType::INTEGER; |
88 | } else if (mask & HOUR_MASK) { |
89 | // HOUR |
90 | fname = "to_hours"; |
91 | target_type = LogicalType::BIGINT; |
92 | } else if (mask & MINUTE_MASK) { |
93 | // MINUTE |
94 | fname = "to_minutes"; |
95 | target_type = LogicalType::BIGINT; |
96 | } else if (mask & SECOND_MASK) { |
97 | // SECOND |
98 | fname = "to_seconds"; |
99 | target_type = LogicalType::BIGINT; |
100 | } else if (mask & MILLISECOND_MASK) { |
101 | // MILLISECOND |
102 | fname = "to_milliseconds"; |
103 | target_type = LogicalType::BIGINT; |
104 | } else if (mask & MICROSECOND_MASK) { |
105 | // SECOND |
106 | fname = "to_microseconds"; |
107 | target_type = LogicalType::BIGINT; |
108 | } else { |
109 | throw InternalException("Unsupported interval post-fix"); |
110 | } |
111 | // first push a cast to the target type |
112 | expr = make_uniq<CastExpression>(args&: target_type, args: std::move(expr)); |
113 | // now push the operation |
114 | vector<unique_ptr<ParsedExpression>> children; |
115 | children.push_back(x: std::move(expr)); |
116 | return make_uniq<FunctionExpression>(args&: fname, args: std::move(children)); |
117 | } |
118 | |
119 | } // namespace duckdb |
120 |