| 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 |