| 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 | |