blob: 6bd29424763cbb24fd89a2fa807b6c592316ba61 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "exprs/operators.h"
#include <functional>
#include <boost/cstdint.hpp>
#include "exprs/anyval-util.h"
#include "gutil/strings/substitute.h"
#include "runtime/string-value.inline.h"
#include "runtime/timestamp-value.h"
#include "util/bit-util.h"
#include "common/names.h"
#define BINARY_OP_FN(NAME, TYPE, OP) \
TYPE Operators::NAME##_##TYPE##_##TYPE(\
FunctionContext* c, const TYPE& v1, const TYPE& v2) {\
if (v1.is_null || v2.is_null) return TYPE::null();\
return TYPE(v1.val OP v2.val);\
}
// Operations on signed integers that overflow are undefined in C++. From the standard:
// [expr] "If during the evaluation of an expression, the result is not mathematically
// defined or not in the range of representable values for its type, the behavior is
// undefined."
//
// Unsigned integers do not suffer the same fate: [basic.fundamental] "unsigned arithmetic
// does not overflow because a result that cannot be represented by the resulting unsigned
// integer type is reduced modulo the number that is one greater than the largest value
// that can be represented by the resulting unsigned integer type."
//
// If we take the bits in two signed values and treat them as unsigned values, the result
// of multiplication, addition, and subtraction are identical to the version of the signed
// operation on a two's complement machine in which overflowing is not undefined, but
// wraps.
#define BINARY_OP_AS_UNSIGNED_FN(NAME, TYPE, OP) \
TYPE Operators::NAME##_##TYPE##_##TYPE( \
FunctionContext* c, const TYPE& v1, const TYPE& v2) { \
if (v1.is_null || v2.is_null) return TYPE::null(); \
return TYPE(ArithmeticUtil::AsUnsigned<OP>(v1.val, v2.val)); \
}
#define BINARY_OP_CHECK_ZERO_FN(NAME, TYPE, OP) \
TYPE Operators::NAME##_##TYPE##_##TYPE(\
FunctionContext* c, const TYPE& v1, const TYPE& v2) {\
if (v1.is_null || v2.is_null || v2.val == 0) return TYPE::null();\
return TYPE(v1.val OP v2.val);\
}
#define BITNOT_FN(TYPE)\
TYPE Operators::Bitnot_##TYPE(FunctionContext* c, const TYPE& v) {\
if (v.is_null) return TYPE::null();\
return TYPE(~v.val);\
}
// Return infinity if overflow.
#define FACTORIAL_FN(TYPE)\
BigIntVal Operators::Factorial_##TYPE(FunctionContext* c, const TYPE& v) {\
if (v.is_null) return BigIntVal::null();\
int64_t fact = ComputeFactorial(v.val); \
if (fact < 0) { \
c->SetError(Substitute("factorial $0! too large for BIGINT", v.val).c_str()); \
return BigIntVal::null(); \
} \
return BigIntVal(fact); \
}
#define BINARY_PREDICATE_NUMERIC_NONNULL(OP, V1, V2) \
return BooleanVal(V1.val OP V2.val)
#define BINARY_PREDICATE_NONNUMERIC_NONNULL(TYPE, IMPALA_TYPE, OP, V1, V2) \
IMPALA_TYPE iv1 = IMPALA_TYPE::From##TYPE(V1);\
IMPALA_TYPE iv2 = IMPALA_TYPE::From##TYPE(V2);\
return BooleanVal(iv1 OP iv2)
#define BINARY_PREDICATE_CHAR_NONNULL(OP, V1, V2) \
StringValue iv1 = StringValue::FromStringVal(V1);\
StringValue iv2 = StringValue::FromStringVal(V2);\
iv1.len = StringValue::UnpaddedCharLength(iv1.ptr, c->GetArgType(0)->len); \
iv2.len = StringValue::UnpaddedCharLength(iv2.ptr, c->GetArgType(1)->len); \
return BooleanVal(iv1 OP iv2)
#define BINARY_PREDICATE_NUMERIC_FN(NAME, TYPE, OP) \
BooleanVal Operators::NAME##_##TYPE##_##TYPE(\
FunctionContext* c, const TYPE& v1, const TYPE& v2) {\
if (v1.is_null || v2.is_null) return BooleanVal::null();\
BINARY_PREDICATE_NUMERIC_NONNULL(OP, v1, v2);\
}
#define BINARY_PREDICATE_NONNUMERIC_FN(NAME, TYPE, IMPALA_TYPE, OP) \
BooleanVal Operators::NAME##_##TYPE##_##TYPE(\
FunctionContext* c, const TYPE& v1, const TYPE& v2) {\
if (v1.is_null || v2.is_null) return BooleanVal::null();\
BINARY_PREDICATE_NONNUMERIC_NONNULL(TYPE, IMPALA_TYPE, OP, v1, v2);\
}
#define BINARY_PREDICATE_CHAR(NAME, OP) \
BooleanVal Operators::NAME##_Char_Char(\
FunctionContext* c, const StringVal& v1, const StringVal& v2) {\
if (v1.is_null || v2.is_null) return BooleanVal::null();\
BINARY_PREDICATE_CHAR_NONNULL(OP, v1, v2);\
}
#define NULLSAFE_NUMERIC_DISTINCTION(NAME, TYPE, OP, IS_EQUAL) \
BooleanVal Operators::NAME##_##TYPE##_##TYPE(\
FunctionContext* c, const TYPE& v1, const TYPE& v2) {\
if (v1.is_null) return BooleanVal(IS_EQUAL ? v2.is_null : !v2.is_null); \
if (v2.is_null) return BooleanVal(!IS_EQUAL);\
BINARY_PREDICATE_NUMERIC_NONNULL(OP, v1, v2);\
}
#define NULLSAFE_NONNUMERIC_DISTINCTION(NAME, TYPE, IMPALA_TYPE, OP, IS_EQUAL) \
BooleanVal Operators::NAME##_##TYPE##_##TYPE(\
FunctionContext* c, const TYPE& v1, const TYPE& v2) {\
if (v1.is_null) return BooleanVal(IS_EQUAL ? v2.is_null : !v2.is_null); \
if (v2.is_null) return BooleanVal(!IS_EQUAL);\
BINARY_PREDICATE_NONNUMERIC_NONNULL(TYPE, IMPALA_TYPE, OP, v1, v2);\
}
#define NULLSAFE_CHAR_DISTINCTION(NAME, OP, IS_EQUAL) \
BooleanVal Operators::NAME##_Char_Char(\
FunctionContext* c, const StringVal& v1, const StringVal& v2) {\
if (v1.is_null) return BooleanVal(IS_EQUAL ? v2.is_null : !v2.is_null); \
if (v2.is_null) return BooleanVal(!IS_EQUAL);\
BINARY_PREDICATE_CHAR_NONNULL(OP, v1, v2);\
}
#define BINARY_OP_AS_UNSIGNED_TYPES(NAME, OP) \
BINARY_OP_AS_UNSIGNED_FN(NAME, TinyIntVal, OP); \
BINARY_OP_AS_UNSIGNED_FN(NAME, SmallIntVal, OP);\
BINARY_OP_AS_UNSIGNED_FN(NAME, IntVal, OP);\
BINARY_OP_AS_UNSIGNED_FN(NAME, BigIntVal, OP);
#define BINARY_OP_FLOAT_TYPES(NAME, OP) \
BINARY_OP_FN(NAME, FloatVal, OP);\
BINARY_OP_FN(NAME, DoubleVal, OP);
#define BINARY_OP_INT_TYPES(NAME, OP) \
BINARY_OP_FN(NAME, TinyIntVal, OP); \
BINARY_OP_FN(NAME, SmallIntVal, OP);\
BINARY_OP_FN(NAME, IntVal, OP);\
BINARY_OP_FN(NAME, BigIntVal, OP);\
#define BINARY_OP_CHECK_ZERO_INT_TYPES(NAME, OP) \
BINARY_OP_CHECK_ZERO_FN(NAME, TinyIntVal, OP); \
BINARY_OP_CHECK_ZERO_FN(NAME, SmallIntVal, OP);\
BINARY_OP_CHECK_ZERO_FN(NAME, IntVal, OP);\
BINARY_OP_CHECK_ZERO_FN(NAME, BigIntVal, OP);\
#define BINARY_PREDICATE_ALL_TYPES(NAME, OP) \
BINARY_PREDICATE_NUMERIC_FN(NAME, BooleanVal, OP); \
BINARY_PREDICATE_NUMERIC_FN(NAME, TinyIntVal, OP); \
BINARY_PREDICATE_NUMERIC_FN(NAME, SmallIntVal, OP);\
BINARY_PREDICATE_NUMERIC_FN(NAME, IntVal, OP);\
BINARY_PREDICATE_NUMERIC_FN(NAME, BigIntVal, OP);\
BINARY_PREDICATE_NUMERIC_FN(NAME, FloatVal, OP);\
BINARY_PREDICATE_NUMERIC_FN(NAME, DoubleVal, OP);\
BINARY_PREDICATE_NUMERIC_FN(NAME, DateVal, OP);\
BINARY_PREDICATE_NONNUMERIC_FN(NAME, StringVal, StringValue, OP);\
BINARY_PREDICATE_NONNUMERIC_FN(NAME, TimestampVal, TimestampValue, OP);\
BINARY_PREDICATE_CHAR(NAME, OP);
#define NULLSAFE_DISTINCTION(NAME, OP, IS_EQUAL) \
NULLSAFE_NUMERIC_DISTINCTION(NAME, BooleanVal, OP, IS_EQUAL); \
NULLSAFE_NUMERIC_DISTINCTION(NAME, TinyIntVal, OP, IS_EQUAL); \
NULLSAFE_NUMERIC_DISTINCTION(NAME, SmallIntVal, OP, IS_EQUAL); \
NULLSAFE_NUMERIC_DISTINCTION(NAME, IntVal, OP, IS_EQUAL); \
NULLSAFE_NUMERIC_DISTINCTION(NAME, BigIntVal, OP, IS_EQUAL); \
NULLSAFE_NUMERIC_DISTINCTION(NAME, FloatVal, OP, IS_EQUAL); \
NULLSAFE_NUMERIC_DISTINCTION(NAME, DoubleVal, OP, IS_EQUAL); \
NULLSAFE_NUMERIC_DISTINCTION(NAME, DateVal, OP, IS_EQUAL); \
NULLSAFE_NONNUMERIC_DISTINCTION(NAME, StringVal, StringValue, OP, IS_EQUAL);\
NULLSAFE_NONNUMERIC_DISTINCTION(NAME, TimestampVal, TimestampValue, OP, IS_EQUAL);\
NULLSAFE_CHAR_DISTINCTION(NAME, OP, IS_EQUAL);
namespace impala {
BINARY_OP_AS_UNSIGNED_TYPES(Add, std::plus);
BINARY_OP_AS_UNSIGNED_TYPES(Subtract, std::minus);
BINARY_OP_AS_UNSIGNED_TYPES(Multiply, std::multiplies);
BINARY_OP_FLOAT_TYPES(Add, +);
BINARY_OP_FLOAT_TYPES(Subtract, -);
BINARY_OP_FLOAT_TYPES(Multiply, *);
BINARY_OP_FN(Divide, DoubleVal, /);
BINARY_OP_CHECK_ZERO_INT_TYPES(Int_divide, /);
BINARY_OP_CHECK_ZERO_INT_TYPES(Mod, %);
BINARY_OP_INT_TYPES(Bitand, &);
BINARY_OP_INT_TYPES(Bitxor, ^);
BINARY_OP_INT_TYPES(Bitor, |);
BITNOT_FN(TinyIntVal);
BITNOT_FN(SmallIntVal);
BITNOT_FN(IntVal);
BITNOT_FN(BigIntVal);
static const int64_t FACTORIAL_MAX = 20;
static const int64_t FACTORIAL_LOOKUP[] = {
1LL, // 0!
1LL, // 1!
2LL, // 2!
6LL, // 3!
24LL, // 4!
120LL, // 5!
720LL, // 6!
5040LL, // 7!
40320LL, // 8!
362880LL, // 9!
3628800LL, // 10!
39916800LL, // 11!
479001600LL, // 12!
6227020800LL, // 13!
87178291200LL, // 14!
1307674368000LL, // 15!
20922789888000LL, // 16!
355687428096000LL, // 17!
6402373705728000LL, // 18!
121645100408832000LL, // 19!
2432902008176640000LL, // 20!
};
// Compute factorial - return -1 if out of range
// Factorial of any number <= 1 returns 1
static int64_t ComputeFactorial(int64_t n) {
// Check range based on arg: 20! < 2^63 -1 < 21!
if (n > FACTORIAL_MAX) {
return -1;
} else if (n < 0) {
return 1;
}
return FACTORIAL_LOOKUP[n];
}
FACTORIAL_FN(TinyIntVal);
FACTORIAL_FN(SmallIntVal);
FACTORIAL_FN(IntVal);
FACTORIAL_FN(BigIntVal);
BINARY_PREDICATE_ALL_TYPES(Eq, ==);
BINARY_PREDICATE_ALL_TYPES(Ne, !=);
BINARY_PREDICATE_ALL_TYPES(Gt, >);
BINARY_PREDICATE_ALL_TYPES(Lt, <);
BINARY_PREDICATE_ALL_TYPES(Ge, >=);
BINARY_PREDICATE_ALL_TYPES(Le, <=);
NULLSAFE_DISTINCTION(DistinctFrom, !=, false);
NULLSAFE_DISTINCTION(NotDistinct, ==, true);
} // namespace impala