1 | #include "duckdb/common/operator/add.hpp" |
2 | |
3 | #include "duckdb/common/limits.hpp" |
4 | #include "duckdb/common/types/value.hpp" |
5 | |
6 | #include "duckdb/common/types/date.hpp" |
7 | #include "duckdb/common/types/interval.hpp" |
8 | #include "duckdb/common/types/timestamp.hpp" |
9 | #include "duckdb/common/types/hugeint.hpp" |
10 | |
11 | namespace duckdb { |
12 | |
13 | //===--------------------------------------------------------------------===// |
14 | // + [add] |
15 | //===--------------------------------------------------------------------===// |
16 | template <> |
17 | float AddOperator::Operation(float left, float right) { |
18 | auto result = left + right; |
19 | return result; |
20 | } |
21 | |
22 | template <> |
23 | double AddOperator::Operation(double left, double right) { |
24 | auto result = left + right; |
25 | return result; |
26 | } |
27 | |
28 | template <> |
29 | interval_t AddOperator::Operation(interval_t left, interval_t right) { |
30 | left.months = AddOperatorOverflowCheck::Operation<int32_t, int32_t, int32_t>(left: left.months, right: right.months); |
31 | left.days = AddOperatorOverflowCheck::Operation<int32_t, int32_t, int32_t>(left: left.days, right: right.days); |
32 | left.micros = AddOperatorOverflowCheck::Operation<int64_t, int64_t, int64_t>(left: left.micros, right: right.micros); |
33 | return left; |
34 | } |
35 | |
36 | template <> |
37 | date_t AddOperator::Operation(date_t left, int32_t right) { |
38 | if (!Value::IsFinite(input: left)) { |
39 | return left; |
40 | } |
41 | int32_t days; |
42 | if (!TryAddOperator::Operation(left: left.days, right, result&: days)) { |
43 | throw OutOfRangeException("Date out of range" ); |
44 | } |
45 | date_t result(days); |
46 | if (!Value::IsFinite(input: result)) { |
47 | throw OutOfRangeException("Date out of range" ); |
48 | } |
49 | return result; |
50 | } |
51 | |
52 | template <> |
53 | date_t AddOperator::Operation(int32_t left, date_t right) { |
54 | return AddOperator::Operation<date_t, int32_t, date_t>(left: right, right: left); |
55 | } |
56 | |
57 | template <> |
58 | timestamp_t AddOperator::Operation(date_t left, dtime_t right) { |
59 | if (left == date_t::infinity()) { |
60 | return timestamp_t::infinity(); |
61 | } else if (left == date_t::ninfinity()) { |
62 | return timestamp_t::ninfinity(); |
63 | } |
64 | timestamp_t result; |
65 | if (!Timestamp::TryFromDatetime(date: left, time: right, result)) { |
66 | throw OutOfRangeException("Timestamp out of range" ); |
67 | } |
68 | return result; |
69 | } |
70 | |
71 | template <> |
72 | timestamp_t AddOperator::Operation(dtime_t left, date_t right) { |
73 | return AddOperator::Operation<date_t, dtime_t, timestamp_t>(left: right, right: left); |
74 | } |
75 | |
76 | template <> |
77 | date_t AddOperator::Operation(date_t left, interval_t right) { |
78 | return Interval::Add(left, right); |
79 | } |
80 | |
81 | template <> |
82 | date_t AddOperator::Operation(interval_t left, date_t right) { |
83 | return AddOperator::Operation<date_t, interval_t, date_t>(left: right, right: left); |
84 | } |
85 | |
86 | template <> |
87 | timestamp_t AddOperator::Operation(timestamp_t left, interval_t right) { |
88 | return Interval::Add(left, right); |
89 | } |
90 | |
91 | template <> |
92 | timestamp_t AddOperator::Operation(interval_t left, timestamp_t right) { |
93 | return AddOperator::Operation<timestamp_t, interval_t, timestamp_t>(left: right, right: left); |
94 | } |
95 | |
96 | //===--------------------------------------------------------------------===// |
97 | // + [add] with overflow check |
98 | //===--------------------------------------------------------------------===// |
99 | struct OverflowCheckedAddition { |
100 | template <class SRCTYPE, class UTYPE> |
101 | static inline bool Operation(SRCTYPE left, SRCTYPE right, SRCTYPE &result) { |
102 | UTYPE uresult = AddOperator::Operation<UTYPE, UTYPE, UTYPE>(UTYPE(left), UTYPE(right)); |
103 | if (uresult < NumericLimits<SRCTYPE>::Minimum() || uresult > NumericLimits<SRCTYPE>::Maximum()) { |
104 | return false; |
105 | } |
106 | result = SRCTYPE(uresult); |
107 | return true; |
108 | } |
109 | }; |
110 | |
111 | template <> |
112 | bool TryAddOperator::Operation(uint8_t left, uint8_t right, uint8_t &result) { |
113 | return OverflowCheckedAddition::Operation<uint8_t, uint16_t>(left, right, result); |
114 | } |
115 | template <> |
116 | bool TryAddOperator::Operation(uint16_t left, uint16_t right, uint16_t &result) { |
117 | return OverflowCheckedAddition::Operation<uint16_t, uint32_t>(left, right, result); |
118 | } |
119 | template <> |
120 | bool TryAddOperator::Operation(uint32_t left, uint32_t right, uint32_t &result) { |
121 | return OverflowCheckedAddition::Operation<uint32_t, uint64_t>(left, right, result); |
122 | } |
123 | |
124 | template <> |
125 | bool TryAddOperator::Operation(uint64_t left, uint64_t right, uint64_t &result) { |
126 | if (NumericLimits<uint64_t>::Maximum() - left < right) { |
127 | return false; |
128 | } |
129 | return OverflowCheckedAddition::Operation<uint64_t, uint64_t>(left, right, result); |
130 | } |
131 | |
132 | template <> |
133 | bool TryAddOperator::Operation(int8_t left, int8_t right, int8_t &result) { |
134 | return OverflowCheckedAddition::Operation<int8_t, int16_t>(left, right, result); |
135 | } |
136 | |
137 | template <> |
138 | bool TryAddOperator::Operation(int16_t left, int16_t right, int16_t &result) { |
139 | return OverflowCheckedAddition::Operation<int16_t, int32_t>(left, right, result); |
140 | } |
141 | |
142 | template <> |
143 | bool TryAddOperator::Operation(int32_t left, int32_t right, int32_t &result) { |
144 | return OverflowCheckedAddition::Operation<int32_t, int64_t>(left, right, result); |
145 | } |
146 | |
147 | template <> |
148 | bool TryAddOperator::Operation(int64_t left, int64_t right, int64_t &result) { |
149 | #if (__GNUC__ >= 5) || defined(__clang__) |
150 | if (__builtin_add_overflow(left, right, &result)) { |
151 | return false; |
152 | } |
153 | #else |
154 | // https://blog.regehr.org/archives/1139 |
155 | result = int64_t((uint64_t)left + (uint64_t)right); |
156 | if ((left < 0 && right < 0 && result >= 0) || (left >= 0 && right >= 0 && result < 0)) { |
157 | return false; |
158 | } |
159 | #endif |
160 | return true; |
161 | } |
162 | |
163 | //===--------------------------------------------------------------------===// |
164 | // add decimal with overflow check |
165 | //===--------------------------------------------------------------------===// |
166 | template <class T, T min, T max> |
167 | bool TryDecimalAddTemplated(T left, T right, T &result) { |
168 | if (right < 0) { |
169 | if (min - right > left) { |
170 | return false; |
171 | } |
172 | } else { |
173 | if (max - right < left) { |
174 | return false; |
175 | } |
176 | } |
177 | result = left + right; |
178 | return true; |
179 | } |
180 | |
181 | template <> |
182 | bool TryDecimalAdd::Operation(int16_t left, int16_t right, int16_t &result) { |
183 | return TryDecimalAddTemplated<int16_t, -9999, 9999>(left, right, result); |
184 | } |
185 | |
186 | template <> |
187 | bool TryDecimalAdd::Operation(int32_t left, int32_t right, int32_t &result) { |
188 | return TryDecimalAddTemplated<int32_t, -999999999, 999999999>(left, right, result); |
189 | } |
190 | |
191 | template <> |
192 | bool TryDecimalAdd::Operation(int64_t left, int64_t right, int64_t &result) { |
193 | return TryDecimalAddTemplated<int64_t, -999999999999999999, 999999999999999999>(left, right, result); |
194 | } |
195 | |
196 | template <> |
197 | bool TryDecimalAdd::Operation(hugeint_t left, hugeint_t right, hugeint_t &result) { |
198 | result = left + right; |
199 | if (result <= -Hugeint::POWERS_OF_TEN[38] || result >= Hugeint::POWERS_OF_TEN[38]) { |
200 | return false; |
201 | } |
202 | return true; |
203 | } |
204 | |
205 | template <> |
206 | hugeint_t DecimalAddOverflowCheck::Operation(hugeint_t left, hugeint_t right) { |
207 | hugeint_t result; |
208 | if (!TryDecimalAdd::Operation(left, right, result)) { |
209 | throw OutOfRangeException("Overflow in addition of DECIMAL(38) (%s + %s);" , left.ToString(), right.ToString()); |
210 | } |
211 | return result; |
212 | } |
213 | |
214 | //===--------------------------------------------------------------------===// |
215 | // add time operator |
216 | //===--------------------------------------------------------------------===// |
217 | template <> |
218 | dtime_t AddTimeOperator::Operation(dtime_t left, interval_t right) { |
219 | date_t date(0); |
220 | return Interval::Add(left, right, date); |
221 | } |
222 | |
223 | template <> |
224 | dtime_t AddTimeOperator::Operation(interval_t left, dtime_t right) { |
225 | return AddTimeOperator::Operation<dtime_t, interval_t, dtime_t>(left: right, right: left); |
226 | } |
227 | |
228 | } // namespace duckdb |
229 | |