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