blob: cffb7ae9781f2db14be2dcfc0f3d5fe8100777d6 [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 "gandiva/precompiled/decimal_ops.h"
#include "gandiva/precompiled/types.h"
extern "C" {
FORCE_INLINE
void add_large_decimal128_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int64_t y_high, uint64_t y_low,
int32_t y_precision, int32_t y_scale,
int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
arrow::BasicDecimal128 out = gandiva::decimalops::Add(x, y, out_precision, out_scale);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void multiply_decimal128_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int64_t y_high, uint64_t y_low,
int32_t y_precision, int32_t y_scale,
int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
bool overflow;
// TODO ravindra: generate error on overflows (ARROW-4570).
arrow::BasicDecimal128 out =
gandiva::decimalops::Multiply(x, y, out_precision, out_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void divide_decimal128_decimal128(int64_t context, int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale, int64_t y_high,
uint64_t y_low, int32_t y_precision, int32_t y_scale,
int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
bool overflow;
// TODO ravindra: generate error on overflows (ARROW-4570).
arrow::BasicDecimal128 out =
gandiva::decimalops::Divide(context, x, y, out_precision, out_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void mod_decimal128_decimal128(int64_t context, int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale, int64_t y_high,
uint64_t y_low, int32_t y_precision, int32_t y_scale,
int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
bool overflow;
// TODO ravindra: generate error on overflows (ARROW-4570).
arrow::BasicDecimal128 out =
gandiva::decimalops::Mod(context, x, y, out_precision, out_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
int32_t compare_decimal128_decimal128_internal(int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale,
int64_t y_high, uint64_t y_low,
int32_t y_precision, int32_t y_scale) {
gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
return gandiva::decimalops::Compare(x, y);
}
FORCE_INLINE
void abs_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision, int32_t x_scale,
int32_t out_precision, int32_t out_scale, int64_t* out_high,
uint64_t* out_low) {
gandiva::BasicDecimal128 x(x_high, x_low);
x.Abs();
*out_high = x.high_bits();
*out_low = x.low_bits();
}
FORCE_INLINE
void ceil_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision, int32_t x_scale,
int32_t out_precision, int32_t out_scale, int64_t* out_high,
uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
auto out = gandiva::decimalops::Ceil(x, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void floor_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
auto out = gandiva::decimalops::Floor(x, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void round_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
auto out = gandiva::decimalops::Round(x, out_precision, 0, 0, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void round_decimal128_int32(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int32_t rounding_scale,
int32_t out_precision, int32_t out_scale, int64_t* out_high,
uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
auto out =
gandiva::decimalops::Round(x, out_precision, out_scale, rounding_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void truncate_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
auto out = gandiva::decimalops::Truncate(x, out_precision, 0, 0, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void truncate_decimal128_int32(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int32_t rounding_scale,
int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
auto out = gandiva::decimalops::Truncate(x, out_precision, out_scale, rounding_scale,
&overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
double castFLOAT8_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
return gandiva::decimalops::ToDouble(x, &overflow);
}
FORCE_INLINE
int64_t castBIGINT_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
return gandiva::decimalops::ToInt64(x, &overflow);
}
FORCE_INLINE
void castDECIMAL_int64(int64_t in, int32_t x_precision, int32_t x_scale,
int64_t* out_high, uint64_t* out_low) {
bool overflow = false;
auto out = gandiva::decimalops::FromInt64(in, x_precision, x_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void castDECIMAL_int32(int32_t in, int32_t x_precision, int32_t x_scale,
int64_t* out_high, uint64_t* out_low) {
castDECIMAL_int64(in, x_precision, x_scale, out_high, out_low);
}
FORCE_INLINE
void castDECIMAL_float64(double in, int32_t x_precision, int32_t x_scale,
int64_t* out_high, uint64_t* out_low) {
bool overflow = false;
auto out = gandiva::decimalops::FromDouble(in, x_precision, x_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
void castDECIMAL_float32(float in, int32_t x_precision, int32_t x_scale,
int64_t* out_high, uint64_t* out_low) {
castDECIMAL_float64(in, x_precision, x_scale, out_high, out_low);
}
FORCE_INLINE
bool castDecimal_internal(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int32_t out_precision, int32_t out_scale,
int64_t* out_high, int64_t* out_low) {
gandiva::BasicDecimalScalar128 x({x_high, x_low}, x_precision, x_scale);
bool overflow = false;
auto out = gandiva::decimalops::Convert(x, out_precision, out_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
return overflow;
}
FORCE_INLINE
void castDECIMAL_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, int32_t out_precision, int32_t out_scale,
int64_t* out_high, int64_t* out_low) {
castDecimal_internal(x_high, x_low, x_precision, x_scale, out_precision, out_scale,
out_high, out_low);
}
FORCE_INLINE
void castDECIMALNullOnOverflow_decimal128(int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale,
bool x_isvalid, bool* out_valid,
int32_t out_precision, int32_t out_scale,
int64_t* out_high, int64_t* out_low) {
*out_valid = true;
if (!x_isvalid) {
*out_valid = false;
return;
}
if (castDecimal_internal(x_high, x_low, x_precision, x_scale, out_precision, out_scale,
out_high, out_low)) {
*out_valid = false;
}
}
FORCE_INLINE
int32_t hash32_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return x_isvalid
? hash32_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, 0)
: 0;
}
FORCE_INLINE
int32_t hash_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return hash32_decimal128(x_high, x_low, x_precision, x_scale, x_isvalid);
}
FORCE_INLINE
int64_t hash64_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return x_isvalid
? hash64_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, 0)
: 0;
}
FORCE_INLINE
int32_t hash32WithSeed_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid, int32_t seed,
gdv_boolean seed_isvalid) {
if (!x_isvalid) {
return seed;
}
return hash32_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, seed);
}
FORCE_INLINE
int64_t hash64WithSeed_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid, int64_t seed,
gdv_boolean seed_isvalid) {
if (!x_isvalid) {
return seed;
}
return hash64_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, seed);
}
FORCE_INLINE
int32_t hash32AsDouble_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return x_isvalid
? hash32_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, 0)
: 0;
}
FORCE_INLINE
int64_t hash64AsDouble_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return x_isvalid
? hash64_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, 0)
: 0;
}
FORCE_INLINE
int32_t hash32AsDoubleWithSeed_decimal128(int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale,
gdv_boolean x_isvalid, int32_t seed,
gdv_boolean seed_isvalid) {
if (!x_isvalid) {
return seed;
}
return hash32_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, seed);
}
FORCE_INLINE
int64_t hash64AsDoubleWithSeed_decimal128(int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale,
gdv_boolean x_isvalid, int64_t seed,
gdv_boolean seed_isvalid) {
if (!x_isvalid) {
return seed;
}
return hash64_buf(gandiva::BasicDecimal128(x_high, x_low).ToBytes().data(), 16, seed);
}
FORCE_INLINE
gdv_boolean isnull_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return !x_isvalid;
}
FORCE_INLINE
gdv_boolean isnotnull_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return x_isvalid;
}
FORCE_INLINE
gdv_boolean isnumeric_decimal128(int64_t x_high, uint64_t x_low, int32_t x_precision,
int32_t x_scale, gdv_boolean x_isvalid) {
return x_isvalid;
}
FORCE_INLINE
gdv_boolean is_not_distinct_from_decimal128_decimal128(
int64_t x_high, uint64_t x_low, int32_t x_precision, int32_t x_scale,
gdv_boolean x_isvalid, int64_t y_high, uint64_t y_low, int32_t y_precision,
int32_t y_scale, gdv_boolean y_isvalid) {
if (x_isvalid != y_isvalid) {
return false;
}
if (!x_isvalid) {
return true;
}
return 0 == compare_decimal128_decimal128_internal(x_high, x_low, x_precision, x_scale,
y_high, y_low, y_precision, y_scale);
}
FORCE_INLINE
gdv_boolean is_distinct_from_decimal128_decimal128(int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale,
gdv_boolean x_isvalid, int64_t y_high,
uint64_t y_low, int32_t y_precision,
int32_t y_scale,
gdv_boolean y_isvalid) {
return !is_not_distinct_from_decimal128_decimal128(x_high, x_low, x_precision, x_scale,
x_isvalid, y_high, y_low,
y_precision, y_scale, y_isvalid);
}
FORCE_INLINE
void castDECIMAL_utf8(int64_t context, const char* in, int32_t in_length,
int32_t out_precision, int32_t out_scale, int64_t* out_high,
uint64_t* out_low) {
int64_t dec_high_from_str;
uint64_t dec_low_from_str;
int32_t precision_from_str;
int32_t scale_from_str;
int32_t status =
gdv_fn_dec_from_string(context, in, in_length, &precision_from_str, &scale_from_str,
&dec_high_from_str, &dec_low_from_str);
if (status != 0) {
*out_high = 0;
*out_low = 0;
return;
}
gandiva::BasicDecimalScalar128 x({dec_high_from_str, dec_low_from_str},
precision_from_str, scale_from_str);
bool overflow = false;
auto out = gandiva::decimalops::Convert(x, out_precision, out_scale, &overflow);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
FORCE_INLINE
char* castVARCHAR_decimal128_int64(int64_t context, int64_t x_high, uint64_t x_low,
int32_t x_precision, int32_t x_scale,
int64_t out_len_param, int32_t* out_length) {
int32_t full_dec_str_len;
char* dec_str =
gdv_fn_dec_to_string(context, x_high, x_low, x_scale, &full_dec_str_len);
int32_t trunc_dec_str_len =
out_len_param < full_dec_str_len ? out_len_param : full_dec_str_len;
*out_length = trunc_dec_str_len;
return dec_str;
}
} // extern "C"