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
7using namespace duckdb;
8using namespace std;
9
10template <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//===--------------------------------------------------------------------===//
89Value ValueOperations::Add(const Value &left, const Value &right) {
90 return templated_binary_operation<duckdb::AddOperator, false>(left, right);
91}
92
93Value ValueOperations::Subtract(const Value &left, const Value &right) {
94 return templated_binary_operation<duckdb::SubtractOperator, false>(left, right);
95}
96
97Value ValueOperations::Multiply(const Value &left, const Value &right) {
98 return templated_binary_operation<duckdb::MultiplyOperator, false>(left, right);
99}
100
101Value 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
137Value 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