1#include "duckdb/parser/expression/constant_expression.hpp"
2#include "duckdb/parser/transformer.hpp"
3#include "duckdb/common/operator/cast_operators.hpp"
4#include "duckdb/common/limits.hpp"
5#include "duckdb/common/types/decimal.hpp"
6
7namespace duckdb {
8
9unique_ptr<ConstantExpression> Transformer::TransformValue(duckdb_libpgquery::PGValue val) {
10 switch (val.type) {
11 case duckdb_libpgquery::T_PGInteger:
12 D_ASSERT(val.val.ival <= NumericLimits<int32_t>::Maximum());
13 return make_uniq<ConstantExpression>(args: Value::INTEGER(value: (int32_t)val.val.ival));
14 case duckdb_libpgquery::T_PGBitString: // FIXME: this should actually convert to BLOB
15 case duckdb_libpgquery::T_PGString:
16 return make_uniq<ConstantExpression>(args: Value(string(val.val.str)));
17 case duckdb_libpgquery::T_PGFloat: {
18 string_t str_val(val.val.str);
19 bool try_cast_as_integer = true;
20 bool try_cast_as_decimal = true;
21 int decimal_position = -1;
22 for (idx_t i = 0; i < str_val.GetSize(); i++) {
23 if (val.val.str[i] == '.') {
24 // decimal point: cast as either decimal or double
25 try_cast_as_integer = false;
26 decimal_position = i;
27 }
28 if (val.val.str[i] == 'e' || val.val.str[i] == 'E') {
29 // found exponent, cast as double
30 try_cast_as_integer = false;
31 try_cast_as_decimal = false;
32 }
33 }
34 if (try_cast_as_integer) {
35 int64_t bigint_value;
36 // try to cast as bigint first
37 if (TryCast::Operation<string_t, int64_t>(input: str_val, result&: bigint_value)) {
38 // successfully cast to bigint: bigint value
39 return make_uniq<ConstantExpression>(args: Value::BIGINT(value: bigint_value));
40 }
41 hugeint_t hugeint_value;
42 // if that is not successful; try to cast as hugeint
43 if (TryCast::Operation<string_t, hugeint_t>(input: str_val, result&: hugeint_value)) {
44 // successfully cast to bigint: bigint value
45 return make_uniq<ConstantExpression>(args: Value::HUGEINT(value: hugeint_value));
46 }
47 }
48 idx_t decimal_offset = val.val.str[0] == '-' ? 3 : 2;
49 if (try_cast_as_decimal && decimal_position >= 0 &&
50 str_val.GetSize() < Decimal::MAX_WIDTH_DECIMAL + decimal_offset) {
51 // figure out the width/scale based on the decimal position
52 auto width = uint8_t(str_val.GetSize() - 1);
53 auto scale = uint8_t(width - decimal_position);
54 if (val.val.str[0] == '-') {
55 width--;
56 }
57 if (width <= Decimal::MAX_WIDTH_DECIMAL) {
58 // we can cast the value as a decimal
59 Value val = Value(str_val);
60 val = val.DefaultCastAs(target_type: LogicalType::DECIMAL(width, scale));
61 return make_uniq<ConstantExpression>(args: std::move(val));
62 }
63 }
64 // if there is a decimal or the value is too big to cast as either hugeint or bigint
65 double dbl_value = Cast::Operation<string_t, double>(input: str_val);
66 return make_uniq<ConstantExpression>(args: Value::DOUBLE(value: dbl_value));
67 }
68 case duckdb_libpgquery::T_PGNull:
69 return make_uniq<ConstantExpression>(args: Value(LogicalType::SQLNULL));
70 default:
71 throw NotImplementedException("Value not implemented!");
72 }
73}
74
75unique_ptr<ParsedExpression> Transformer::TransformConstant(duckdb_libpgquery::PGAConst &c) {
76 return TransformValue(val: c.val);
77}
78
79} // namespace duckdb
80