1 | #include "duckdb/common/exception.hpp" |
2 | #include "duckdb/common/limits.hpp" |
3 | #include "duckdb/common/operator/numeric_binary_operators.hpp" |
4 | #include "duckdb/common/value_operations/value_operations.hpp" |
5 | #include "duckdb/common/operator/aggregate_operators.hpp" |
6 | |
7 | using namespace duckdb; |
8 | using namespace std; |
9 | |
10 | template <class OP, bool IGNORE_NULL> static Value templated_binary_operation(const Value &left, const Value &right) { |
11 | Value result; |
12 | if (left.is_null || right.is_null) { |
13 | if (IGNORE_NULL) { |
14 | if (!right.is_null) { |
15 | result = right; |
16 | } else { |
17 | result = left; |
18 | } |
19 | } else { |
20 | result.type = max(left.type, right.type); |
21 | result.is_null = true; |
22 | } |
23 | return result; |
24 | } |
25 | result.is_null = false; |
26 | if (left.type != right.type) { |
27 | if (TypeIsIntegral(left.type) && TypeIsIntegral(right.type) && |
28 | (left.type < TypeId::INT64 || right.type < TypeId::INT64)) { |
29 | // upcast integer types if necessary |
30 | Value left_cast = left.CastAs(TypeId::INT64); |
31 | Value right_cast = right.CastAs(TypeId::INT64); |
32 | result = templated_binary_operation<OP, IGNORE_NULL>(left_cast, right_cast); |
33 | if (result.is_null) { |
34 | result.type = max(left.type, right.type); |
35 | } else { |
36 | auto type = max(MinimalType(result.GetValue<int64_t>()), max(left.type, right.type)); |
37 | result = result.CastAs(type); |
38 | } |
39 | return result; |
40 | } |
41 | if (TypeIsIntegral(left.type) && TypeIsNumeric(right.type)) { |
42 | Value left_cast = left.CastAs(right.type); |
43 | return templated_binary_operation<OP, IGNORE_NULL>(left_cast, right); |
44 | } |
45 | if (TypeIsNumeric(left.type) && TypeIsIntegral(right.type)) { |
46 | Value right_cast = right.CastAs(left.type); |
47 | return templated_binary_operation<OP, IGNORE_NULL>(left, right_cast); |
48 | } |
49 | throw TypeMismatchException(left.type, right.type, "Cannot perform binary operation on these two types" ); |
50 | } |
51 | result.type = left.type; |
52 | switch (left.type) { |
53 | case TypeId::INT8: |
54 | result.value_.tinyint = |
55 | OP::template Operation<int8_t, int8_t, int8_t>(left.value_.tinyint, right.value_.tinyint); |
56 | break; |
57 | case TypeId::INT16: |
58 | result.value_.smallint = |
59 | OP::template Operation<int16_t, int16_t, int16_t>(left.value_.smallint, right.value_.smallint); |
60 | break; |
61 | case TypeId::INT32: |
62 | result.value_.integer = |
63 | OP::template Operation<int32_t, int32_t, int32_t>(left.value_.integer, right.value_.integer); |
64 | break; |
65 | case TypeId::INT64: |
66 | result.value_.bigint = |
67 | OP::template Operation<int64_t, int64_t, int64_t>(left.value_.bigint, right.value_.bigint); |
68 | break; |
69 | case TypeId::FLOAT: |
70 | result.value_.float_ = OP::template Operation<float, float, float>(left.value_.float_, right.value_.float_); |
71 | break; |
72 | case TypeId::DOUBLE: |
73 | result.value_.double_ = |
74 | OP::template Operation<double, double, double>(left.value_.double_, right.value_.double_); |
75 | break; |
76 | case TypeId::POINTER: |
77 | result.value_.pointer = |
78 | OP::template Operation<uint64_t, uint64_t, uint64_t>(left.value_.pointer, right.value_.pointer); |
79 | break; |
80 | default: |
81 | throw NotImplementedException("Unimplemented type" ); |
82 | } |
83 | return result; |
84 | } |
85 | |
86 | //===--------------------------------------------------------------------===// |
87 | // Numeric Operations |
88 | //===--------------------------------------------------------------------===// |
89 | Value ValueOperations::Add(const Value &left, const Value &right) { |
90 | return templated_binary_operation<duckdb::AddOperator, false>(left, right); |
91 | } |
92 | |
93 | Value ValueOperations::Subtract(const Value &left, const Value &right) { |
94 | return templated_binary_operation<duckdb::SubtractOperator, false>(left, right); |
95 | } |
96 | |
97 | Value ValueOperations::Multiply(const Value &left, const Value &right) { |
98 | return templated_binary_operation<duckdb::MultiplyOperator, false>(left, right); |
99 | } |
100 | |
101 | Value ValueOperations::Modulo(const Value &left, const Value &right) { |
102 | if (!TypeIsIntegral(left.type) || !TypeIsIntegral(right.type)) { |
103 | throw InvalidTypeException(left.type, "Arguments to modulo must be integral" ); |
104 | } |
105 | if (left.type != right.type) { |
106 | if (left.type < right.type) { |
107 | return Modulo(left.CastAs(right.type), right); |
108 | } else { |
109 | return Modulo(left, right.CastAs(left.type)); |
110 | } |
111 | } |
112 | if (left.is_null || right.is_null) { |
113 | return Value(left.type); |
114 | } |
115 | Value result; |
116 | result.is_null = false; |
117 | result.type = left.type; |
118 | switch (left.type) { |
119 | case TypeId::INT8: |
120 | return Value::TINYINT(left.value_.tinyint % right.value_.tinyint); |
121 | break; |
122 | case TypeId::INT16: |
123 | return Value::SMALLINT(left.value_.smallint % right.value_.smallint); |
124 | break; |
125 | case TypeId::INT32: |
126 | return Value::INTEGER(left.value_.integer % right.value_.integer); |
127 | break; |
128 | case TypeId::INT64: |
129 | result.value_.bigint = left.value_.bigint % right.value_.bigint; |
130 | break; |
131 | default: |
132 | throw NotImplementedException("Unimplemented type for modulo" ); |
133 | } |
134 | return result; |
135 | } |
136 | |
137 | Value ValueOperations::Divide(const Value &left, const Value &right) { |
138 | Value zero = Value::Numeric(right.type, 0); |
139 | if (right == 0) { |
140 | // special case: divide by zero |
141 | Value result; |
142 | result.type = max(left.type, right.type); |
143 | result.is_null = true; |
144 | return result; |
145 | } else { |
146 | return templated_binary_operation<duckdb::DivideOperator, false>(left, right); |
147 | } |
148 | } |
149 | |
150 | // Value ValueOperations::Min(const Value &left, const Value &right) { |
151 | // return templated_binary_operation<duckdb::Min, true>(left, right); |
152 | // } |
153 | |
154 | // Value ValueOperations::Max(const Value &left, const Value &right) { |
155 | // return templated_binary_operation<duckdb::Max, true>(left, right); |
156 | // } |
157 | |