blob: 2bd31bd7887032bf75c76ee151e59416f6a196ef [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 <cmath>
#include <cstdint>
#include "arrow/util/basic_decimal.h"
extern "C" {
#include "./types.h"
// Expand inner macro for all numeric types.
#define NUMERIC_TYPES(INNER, NAME, OP) \
INNER(NAME, int8, OP) \
INNER(NAME, int16, OP) \
INNER(NAME, int32, OP) \
INNER(NAME, int64, OP) \
INNER(NAME, uint8, OP) \
INNER(NAME, uint16, OP) \
INNER(NAME, uint32, OP) \
INNER(NAME, uint64, OP) \
INNER(NAME, float32, OP) \
INNER(NAME, float64, OP)
// Expand inner macros for all date/time types.
#define DATE_TYPES(INNER, NAME, OP) \
INNER(NAME, date64, OP) \
INNER(NAME, date32, OP) \
INNER(NAME, timestamp, OP) \
INNER(NAME, time32, OP)
#define NUMERIC_DATE_TYPES(INNER, NAME, OP) \
NUMERIC_TYPES(INNER, NAME, OP) \
DATE_TYPES(INNER, NAME, OP)
#define NUMERIC_BOOL_DATE_TYPES(INNER, NAME, OP) \
NUMERIC_TYPES(INNER, NAME, OP) \
DATE_TYPES(INNER, NAME, OP) \
INNER(NAME, boolean, OP)
#define MOD_OP(NAME, IN_TYPE1, IN_TYPE2, OUT_TYPE) \
FORCE_INLINE \
gdv_##OUT_TYPE NAME##_##IN_TYPE1##_##IN_TYPE2(gdv_##IN_TYPE1 left, \
gdv_##IN_TYPE2 right) { \
return (right == 0 ? static_cast<gdv_##OUT_TYPE>(left) \
: static_cast<gdv_##OUT_TYPE>(left % right)); \
}
#define PMOD_OP(NAME, IN_TYPE1, IN_TYPE2, OUT_TYPE) \
FORCE_INLINE \
gdv_##OUT_TYPE NAME##_##IN_TYPE1##_##IN_TYPE2(int64_t context, gdv_##IN_TYPE1 left, \
gdv_##IN_TYPE2 right) { \
if (right == static_cast<gdv_##IN_TYPE2>(0)) { \
gdv_fn_context_set_error_msg(context, "divide by zero error"); \
return static_cast<gdv_##IN_TYPE1>(0); \
} \
double mod = fmod(static_cast<double>(left), static_cast<double>(right)); \
if (mod < 0 || right < 0) { \
mod += static_cast<double>(right); \
} \
return static_cast<gdv_##IN_TYPE1>(mod); \
}
// Symmetric binary fns : left, right params and return type are same.
#define BINARY_SYMMETRIC(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_##TYPE##_##TYPE(gdv_##TYPE left, gdv_##TYPE right) { \
return static_cast<gdv_##TYPE>(left OP right); \
}
NUMERIC_TYPES(BINARY_SYMMETRIC, add, +)
NUMERIC_TYPES(BINARY_SYMMETRIC, subtract, -)
NUMERIC_TYPES(BINARY_SYMMETRIC, multiply, *)
BINARY_SYMMETRIC(bitwise_and, int32, &)
BINARY_SYMMETRIC(bitwise_and, int64, &)
BINARY_SYMMETRIC(bitwise_or, int32, |)
BINARY_SYMMETRIC(bitwise_or, int64, |)
BINARY_SYMMETRIC(bitwise_xor, int32, ^)
BINARY_SYMMETRIC(bitwise_xor, int64, ^)
#undef BINARY_SYMMETRIC
MOD_OP(mod, int64, int32, int32)
MOD_OP(mod, int64, int64, int64)
MOD_OP(mod, uint32, uint32, uint32)
MOD_OP(mod, uint64, uint64, uint64)
PMOD_OP(pmod, int32, int32, int32)
PMOD_OP(pmod, int64, int64, int64)
PMOD_OP(pmod, float32, float32, float32)
PMOD_OP(pmod, float64, float64, float64)
#undef MOD_OP
#undef PMOD_OP
gdv_float64 mod_float64_float64(int64_t context, gdv_float64 x, gdv_float64 y) {
if (y == 0.0) {
const char* err_msg = "divide by zero error";
gdv_fn_context_set_error_msg(context, err_msg);
return 0.0;
}
return fmod(x, y);
}
// Relational binary fns : left, right params are same, return is bool.
#define BINARY_RELATIONAL(NAME, TYPE, OP) \
FORCE_INLINE \
bool NAME##_##TYPE##_##TYPE(gdv_##TYPE left, gdv_##TYPE right) { return left OP right; }
NUMERIC_BOOL_DATE_TYPES(BINARY_RELATIONAL, equal, ==)
NUMERIC_BOOL_DATE_TYPES(BINARY_RELATIONAL, not_equal, !=)
NUMERIC_DATE_TYPES(BINARY_RELATIONAL, less_than, <)
NUMERIC_DATE_TYPES(BINARY_RELATIONAL, less_than_or_equal_to, <=)
NUMERIC_DATE_TYPES(BINARY_RELATIONAL, greater_than, >)
NUMERIC_DATE_TYPES(BINARY_RELATIONAL, greater_than_or_equal_to, >=)
#undef BINARY_RELATIONAL
// Returns the greatest or least value from a list of values
#define COMPARE_TWO_VALUES(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_##TYPE##_##TYPE(gdv_##TYPE in1, gdv_##TYPE in2) { \
return (in1 OP in2 ? in1 : in2); \
}
#define COMPARE_THREE_VALUES(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_##TYPE##_##TYPE##_##TYPE(gdv_##TYPE in1, gdv_##TYPE in2, \
gdv_##TYPE in3) { \
gdv_##TYPE compared = (in1 OP in2 ? in1 : in2); \
return (compared OP in3 ? compared : in3); \
}
#define COMPARE_FOUR_VALUES(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_##TYPE##_##TYPE##_##TYPE##_##TYPE(gdv_##TYPE in1, gdv_##TYPE in2, \
gdv_##TYPE in3, gdv_##TYPE in4) { \
gdv_##TYPE compared = (in1 OP in2 ? in1 : in2); \
compared = (compared OP in3 ? compared : in3); \
return (compared OP in4 ? compared : in4); \
}
#define COMPARE_FIVE_VALUES(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_##TYPE##_##TYPE##_##TYPE##_##TYPE##_##TYPE( \
gdv_##TYPE in1, gdv_##TYPE in2, gdv_##TYPE in3, gdv_##TYPE in4, gdv_##TYPE in5) { \
gdv_##TYPE compared = (in1 OP in2 ? in1 : in2); \
compared = (compared OP in3 ? compared : in3); \
compared = (compared OP in4 ? compared : in4); \
return (compared OP in5 ? compared : in5); \
}
#define COMPARE_SIX_VALUES(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_##TYPE##_##TYPE##_##TYPE##_##TYPE##_##TYPE##_##TYPE( \
gdv_##TYPE in1, gdv_##TYPE in2, gdv_##TYPE in3, gdv_##TYPE in4, gdv_##TYPE in5, \
gdv_##TYPE in6) { \
gdv_##TYPE compared = (in1 OP in2 ? in1 : in2); \
compared = (compared OP in3 ? compared : in3); \
compared = (compared OP in4 ? compared : in4); \
compared = (compared OP in5 ? compared : in5); \
return (compared OP in6 ? compared : in6); \
}
NUMERIC_DATE_TYPES(COMPARE_TWO_VALUES, greatest, >)
NUMERIC_DATE_TYPES(COMPARE_TWO_VALUES, least, <)
NUMERIC_DATE_TYPES(COMPARE_THREE_VALUES, greatest, >)
NUMERIC_DATE_TYPES(COMPARE_THREE_VALUES, least, <)
NUMERIC_DATE_TYPES(COMPARE_FOUR_VALUES, greatest, >)
NUMERIC_DATE_TYPES(COMPARE_FOUR_VALUES, least, <)
NUMERIC_DATE_TYPES(COMPARE_FIVE_VALUES, greatest, >)
NUMERIC_DATE_TYPES(COMPARE_FIVE_VALUES, least, <)
NUMERIC_DATE_TYPES(COMPARE_SIX_VALUES, greatest, >)
NUMERIC_DATE_TYPES(COMPARE_SIX_VALUES, least, <)
#undef COMPARE_TWO_VALUES
#undef COMPARE_THREE_VALUES
#undef COMPARE_FOUR_VALUES
#undef COMPARE_FIVE_VALUES
#undef COMPARE_SIX_VALUES
// cast fns : takes one param type, returns another type.
#define CAST_UNARY(NAME, IN_TYPE, OUT_TYPE) \
FORCE_INLINE \
gdv_##OUT_TYPE NAME##_##IN_TYPE(gdv_##IN_TYPE in) { \
return static_cast<gdv_##OUT_TYPE>(in); \
}
CAST_UNARY(castBIGINT, int32, int64)
CAST_UNARY(castINT, int64, int32)
CAST_UNARY(castFLOAT4, int32, float32)
CAST_UNARY(castFLOAT4, int64, float32)
CAST_UNARY(castFLOAT8, int32, float64)
CAST_UNARY(castFLOAT8, int64, float64)
CAST_UNARY(castFLOAT8, float32, float64)
CAST_UNARY(castFLOAT4, float64, float32)
#undef CAST_UNARY
// cast float types to int types.
#define CAST_INT_FLOAT(NAME, IN_TYPE, OUT_TYPE) \
FORCE_INLINE \
gdv_##OUT_TYPE NAME##_##IN_TYPE(gdv_##IN_TYPE in) { \
gdv_##OUT_TYPE out = static_cast<gdv_##OUT_TYPE>(round(in)); \
return out; \
}
CAST_INT_FLOAT(castBIGINT, float32, int64)
CAST_INT_FLOAT(castBIGINT, float64, int64)
CAST_INT_FLOAT(castINT, float32, int32)
CAST_INT_FLOAT(castINT, float64, int32)
#undef CAST_INT_FLOAT
// simple nullable functions, result value = fn(input validity)
#define VALIDITY_OP(NAME, TYPE, OP) \
FORCE_INLINE \
bool NAME##_##TYPE(gdv_##TYPE in, gdv_boolean is_valid) { return OP is_valid; }
NUMERIC_BOOL_DATE_TYPES(VALIDITY_OP, isnull, !)
NUMERIC_BOOL_DATE_TYPES(VALIDITY_OP, isnotnull, +)
NUMERIC_TYPES(VALIDITY_OP, isnumeric, +)
#undef VALIDITY_OP
#define IS_TRUE_OR_FALSE_BOOL(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_boolean(gdv_##TYPE in, gdv_boolean is_valid) { \
return is_valid && OP in; \
}
IS_TRUE_OR_FALSE_BOOL(istrue, boolean, +)
IS_TRUE_OR_FALSE_BOOL(isfalse, boolean, !)
#define IS_NOT_TRUE_OR_IS_NOT_FALSE_BOOL(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_##TYPE NAME##_boolean(gdv_##TYPE in, gdv_boolean is_valid) { \
return !is_valid || OP in; \
}
IS_NOT_TRUE_OR_IS_NOT_FALSE_BOOL(isnottrue, boolean, !)
IS_NOT_TRUE_OR_IS_NOT_FALSE_BOOL(isnotfalse, boolean, +)
#define IS_TRUE_OR_FALSE_NUMERIC(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_boolean NAME##_##TYPE(gdv_##TYPE in, gdv_boolean is_valid) { \
return is_valid && OP(in != 0); \
}
NUMERIC_TYPES(IS_TRUE_OR_FALSE_NUMERIC, istrue, +)
NUMERIC_TYPES(IS_TRUE_OR_FALSE_NUMERIC, isfalse, !)
#define IS_NOT_TRUE_OR_IS_NOT_FALSE_NUMERIC(NAME, TYPE, OP) \
FORCE_INLINE \
gdv_boolean NAME##_##TYPE(gdv_##TYPE in, gdv_boolean is_valid) { \
return !is_valid || OP(in != 0); \
}
NUMERIC_TYPES(IS_NOT_TRUE_OR_IS_NOT_FALSE_NUMERIC, isnottrue, !)
NUMERIC_TYPES(IS_NOT_TRUE_OR_IS_NOT_FALSE_NUMERIC, isnotfalse, +)
#define NUMERIC_FUNCTION_FOR_REAL(INNER) \
INNER(float32) \
INNER(float64)
#define NUMERIC_FUNCTION(INNER) \
INNER(int8) \
INNER(int16) \
INNER(int32) \
INNER(int64) \
INNER(uint8) \
INNER(uint16) \
INNER(uint32) \
INNER(uint64) \
NUMERIC_FUNCTION_FOR_REAL(INNER)
#define DATE_FUNCTION(INNER) \
INNER(date32) \
INNER(date64) \
INNER(timestamp) \
INNER(time32)
#define NUMERIC_BOOL_DATE_FUNCTION(INNER) \
NUMERIC_FUNCTION(INNER) \
DATE_FUNCTION(INNER) \
INNER(boolean)
#define NVL(TYPE) \
FORCE_INLINE \
gdv_##TYPE nvl_##TYPE##_##TYPE(gdv_##TYPE in, gdv_boolean is_valid_in, \
gdv_##TYPE replace, gdv_boolean is_valid_value) { \
return (is_valid_in ? in : replace); \
}
NUMERIC_BOOL_DATE_FUNCTION(NVL)
#undef NVL
FORCE_INLINE
gdv_boolean not_boolean(gdv_boolean in) { return !in; }
// is_distinct_from
#define IS_DISTINCT_FROM(TYPE) \
FORCE_INLINE \
bool is_distinct_from_##TYPE##_##TYPE(gdv_##TYPE in1, gdv_boolean is_valid1, \
gdv_##TYPE in2, gdv_boolean is_valid2) { \
if (is_valid1 != is_valid2) { \
return true; \
} \
if (!is_valid1) { \
return false; \
} \
return in1 != in2; \
}
// is_not_distinct_from
#define IS_NOT_DISTINCT_FROM(TYPE) \
FORCE_INLINE \
bool is_not_distinct_from_##TYPE##_##TYPE(gdv_##TYPE in1, gdv_boolean is_valid1, \
gdv_##TYPE in2, gdv_boolean is_valid2) { \
if (is_valid1 != is_valid2) { \
return false; \
} \
if (!is_valid1) { \
return true; \
} \
return in1 == in2; \
}
NUMERIC_BOOL_DATE_FUNCTION(IS_DISTINCT_FROM)
NUMERIC_BOOL_DATE_FUNCTION(IS_NOT_DISTINCT_FROM)
#undef IS_DISTINCT_FROM
#undef IS_NOT_DISTINCT_FROM
#define DIVIDE(TYPE) \
FORCE_INLINE \
gdv_##TYPE divide_##TYPE##_##TYPE(gdv_int64 context, gdv_##TYPE in1, gdv_##TYPE in2) { \
if (in2 == 0) { \
const char* err_msg = "divide by zero error"; \
gdv_fn_context_set_error_msg(context, err_msg); \
return 0; \
} \
return static_cast<gdv_##TYPE>(in1 / in2); \
}
NUMERIC_FUNCTION(DIVIDE)
#undef DIVIDE
#define POSITIVE(TYPE) \
FORCE_INLINE \
gdv_##TYPE positive_##TYPE(gdv_##TYPE in) { return in; }
NUMERIC_FUNCTION(POSITIVE)
#undef POSITIVE
#define NEGATIVE(TYPE) \
FORCE_INLINE \
gdv_##TYPE negative_##TYPE(gdv_##TYPE in) { return static_cast<gdv_##TYPE>(-1 * in); }
NUMERIC_FUNCTION_FOR_REAL(NEGATIVE)
#define NEGATIVE_INTEGER(TYPE, SIZE) \
FORCE_INLINE \
gdv_##TYPE negative_##TYPE(gdv_int64 context, gdv_##TYPE in) { \
if (in <= INT##SIZE##_MIN) { \
gdv_fn_context_set_error_msg(context, "Overflow in negative execution"); \
return 0; \
} \
return -1 * in; \
}
NEGATIVE_INTEGER(int32, 32)
NEGATIVE_INTEGER(int64, 64)
NEGATIVE_INTEGER(month_interval, 32)
const int64_t INT_MAX_TO_NEGATIVE_INTERVAL_DAY_TIME = 9223372034707292159;
const int64_t INT_MIN_TO_NEGATIVE_INTERVAL_DAY_TIME = -9223372030412324863;
gdv_int64 negative_daytimeinterval(gdv_int64 context, gdv_day_time_interval interval) {
if (interval > INT_MAX_TO_NEGATIVE_INTERVAL_DAY_TIME ||
interval < INT_MIN_TO_NEGATIVE_INTERVAL_DAY_TIME) {
gdv_fn_context_set_error_msg(
context, "Interval day time is out of boundaries for the negative function");
return 0;
}
int64_t left = interval >> 32;
int64_t right = interval & 0x00000000FFFFFFFF;
left = -1 * left;
right = -1 * right;
gdv_int64 out = (left & 0x00000000FFFFFFFF) << 32;
out |= (right & 0x00000000FFFFFFFF);
return out;
}
#undef NEGATIVE
#undef NEGATIVE_INTEGER
void negative_decimal(gdv_int64 context, int64_t high_bits, uint64_t low_bits,
int32_t /*precision*/, int32_t /*scale*/, int32_t /*out_precision*/,
int32_t /*out_scale*/, int64_t* out_high_bits,
uint64_t* out_low_bits) {
arrow::BasicDecimal128 res = arrow::BasicDecimal128(high_bits, low_bits).Negate();
*out_high_bits = res.high_bits();
*out_low_bits = res.low_bits();
}
#define DIV(TYPE) \
FORCE_INLINE \
gdv_##TYPE div_##TYPE##_##TYPE(gdv_int64 context, gdv_##TYPE in1, gdv_##TYPE in2) { \
if (in2 == 0) { \
const char* err_msg = "divide by zero error"; \
gdv_fn_context_set_error_msg(context, err_msg); \
return 0; \
} \
return static_cast<gdv_##TYPE>(in1 / in2); \
}
DIV(int32)
DIV(int64)
DIV(uint32)
DIV(uint64)
#undef DIV
#define DIV_FLOAT(TYPE) \
FORCE_INLINE \
gdv_##TYPE div_##TYPE##_##TYPE(gdv_int64 context, gdv_##TYPE in1, gdv_##TYPE in2) { \
if (in2 == 0) { \
const char* err_msg = "divide by zero error"; \
gdv_fn_context_set_error_msg(context, err_msg); \
return 0; \
} \
return static_cast<gdv_##TYPE>(::trunc(in1 / in2)); \
}
DIV_FLOAT(float32)
DIV_FLOAT(float64)
#undef DIV_FLOAT
#define BITWISE_NOT(TYPE) \
FORCE_INLINE \
gdv_##TYPE bitwise_not_##TYPE(gdv_##TYPE in) { return static_cast<gdv_##TYPE>(~in); }
BITWISE_NOT(int32)
BITWISE_NOT(int64)
#undef BITWISE_NOT
#undef DATE_FUNCTION
#undef DATE_TYPES
#undef NUMERIC_BOOL_DATE_TYPES
#undef NUMERIC_DATE_TYPES
#define SIGN(TYPE) \
FORCE_INLINE \
gdv_##TYPE sign_##TYPE(gdv_##TYPE in1) { \
gdv_##TYPE out; \
if (in1 > 0) { \
out = static_cast<gdv_##TYPE>(1); \
} else if (in1 < 0) { \
out = static_cast<gdv_##TYPE>(-1); \
} else { \
out = in1; \
} \
return out; \
}
SIGN(int32)
SIGN(int64)
SIGN(float32)
SIGN(float64)
#undef SIGN
#define ABS(TYPE) \
FORCE_INLINE \
gdv_##TYPE abs_##TYPE(gdv_##TYPE in1) { return static_cast<gdv_##TYPE>(std::abs(in1)); }
ABS(int32)
ABS(int64)
ABS(float32)
ABS(float64)
#undef ABS
#define CEILING(TYPE) \
FORCE_INLINE \
gdv_##TYPE ceiling_##TYPE(gdv_##TYPE in1) { return static_cast<gdv_##TYPE>(ceil(in1)); }
CEILING(float32)
CEILING(float64)
#undef CEILING
#define FLOOR(TYPE) \
FORCE_INLINE \
gdv_##TYPE floor_##TYPE(gdv_##TYPE in1) { return static_cast<gdv_##TYPE>(floor(in1)); }
FLOOR(float32)
FLOOR(float64)
#undef FLOOR
#define SQRT(TYPE) \
FORCE_INLINE \
gdv_float64 sqrt_##TYPE(gdv_##TYPE in1) { \
if (in1 < 0) { \
return NAN; \
} \
return static_cast<gdv_float64>(sqrt(in1)); \
}
SQRT(int32)
SQRT(int64)
SQRT(float32)
SQRT(float64)
#undef SQRT
#undef NUMERIC_FUNCTION
#undef NUMERIC_TYPES
} // extern "C"