From 7a0cc27fd1113d924cf538df991acaaeeb169204 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 9 Jul 2014 11:58:26 -0700 Subject: [PATCH] Convert math functions to the UDF interface. Also adds FunctionContext::GetNumArgs() method to the public UDF API. Change-Id: I76e21814e423f075a0a22b4e924c1d3ec26daba7 Reviewed-on: http://gerrit.sjc.cloudera.com:8080/3410 Reviewed-by: Skye Wanderman-Milne Tested-by: Skye Wanderman-Milne --- be/src/codegen/CMakeLists.txt | 1 + be/src/codegen/impala-ir.cc | 1 + be/src/exprs/expr.cc | 2 +- be/src/exprs/math-functions.cc | 788 +++++++----------- be/src/exprs/math-functions.h | 107 ++- be/src/udf/udf.cc | 4 + be/src/udf/udf.h | 4 + common/function-registry/impala_functions.py | 202 ++--- .../impala/analysis/ArithmeticExpr.java | 7 +- .../queries/QueryTest/exprs.test | 8 + 10 files changed, 511 insertions(+), 613 deletions(-) diff --git a/be/src/codegen/CMakeLists.txt b/be/src/codegen/CMakeLists.txt index 42f3ae108..f461308bb 100644 --- a/be/src/codegen/CMakeLists.txt +++ b/be/src/codegen/CMakeLists.txt @@ -59,6 +59,7 @@ set(IR_DEPENDENT_FILES ../exprs/decimal-functions.cc ../exprs/decimal-operators.cc ../exprs/expr-ir.cc + ../exprs/math-functions.cc ../exprs/operators.cc ../exprs/udf-builtins.cc ../exprs/like-predicate.cc diff --git a/be/src/codegen/impala-ir.cc b/be/src/codegen/impala-ir.cc index 2d83059c7..47ece7034 100644 --- a/be/src/codegen/impala-ir.cc +++ b/be/src/codegen/impala-ir.cc @@ -27,6 +27,7 @@ #include "exprs/decimal-functions.cc" #include "exprs/decimal-operators.cc" #include "exprs/expr-ir.cc" +#include "exprs/math-functions.cc" #include "exprs/operators.cc" #include "exprs/udf-builtins.cc" #include "runtime/string-value-ir.cc" diff --git a/be/src/exprs/expr.cc b/be/src/exprs/expr.cc index be8f97205..117d0cfae 100644 --- a/be/src/exprs/expr.cc +++ b/be/src/exprs/expr.cc @@ -1020,7 +1020,7 @@ void Expr::InitBuiltinsDummy() { ConditionalFunctions::IsNull(NULL, NULL); DecimalFunctions::Precision(NULL, DecimalVal::null()); DecimalOperators::CastToDecimalVal(NULL, DecimalVal::null()); - MathFunctions::Pi(NULL, NULL); + MathFunctions::Pi(NULL); Operators::Add_IntVal_IntVal(NULL, IntVal::null(), IntVal::null()); StringFunctions::Length(NULL, NULL); TimestampFunctions::Year(NULL, TimestampVal::null()); diff --git a/be/src/exprs/math-functions.cc b/be/src/exprs/math-functions.cc index 2945c57c9..1a7df3f9f 100644 --- a/be/src/exprs/math-functions.cc +++ b/be/src/exprs/math-functions.cc @@ -18,10 +18,10 @@ #include #include +#include "exprs/anyval-util.h" #include "exprs/expr.h" #include "exprs/expr-inline.h" #include "exprs/operators.h" -#include "runtime/tuple-row.h" #include "util/string-parser.h" using namespace std; @@ -30,274 +30,168 @@ namespace impala { const char* MathFunctions::ALPHANUMERIC_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -void* MathFunctions::Pi(Expr* e, TupleRow* row) { - e->result_.double_val = M_PI; - return &e->result_.double_val; +DoubleVal MathFunctions::Pi(FunctionContext* ctx) { + return DoubleVal(M_PI); } -void* MathFunctions::E(Expr* e, TupleRow* row) { - e->result_.double_val = M_E; - return &e->result_.double_val; +DoubleVal MathFunctions::E(FunctionContext* ctx) { + return DoubleVal(M_E); } -void* MathFunctions::Abs(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = fabs(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Sign(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.float_val = (*d > 0) ? 1.0f : ((*d < 0) ? -1.0f : 0.0f); - return &e->result_.float_val; -} - -void* MathFunctions::Sin(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = sin(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Asin(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = asin(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Cos(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = cos(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Acos(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = acos(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Tan(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = tan(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Atan(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = atan(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Radians(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = *d * M_PI / 180.0; - return &e->result_.double_val; -} - -void* MathFunctions::Degrees(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = *d * 180 / M_PI; - return &e->result_.double_val; -} - -void* MathFunctions::Ceil(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.bigint_val = ceil(*d); - return &e->result_.bigint_val; -} - -void* MathFunctions::Floor(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.bigint_val = floor(*d); - return &e->result_.bigint_val; -} - -void* MathFunctions::Round(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.bigint_val = static_cast(*d + ((*d < 0) ? -0.5 : 0.5)); - return &e->result_.bigint_val; -} - -void* MathFunctions::RoundUpTo(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 2); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - int32_t* scale = reinterpret_cast(e->children()[1]->GetValue(row)); - if (d == NULL || scale == NULL) return NULL; - e->result_.double_val = floor(*d * pow(10.0, *scale) + 0.5) / pow(10.0, *scale); - e->output_scale_ = *scale; - return &e->result_.double_val; -} - -void* MathFunctions::Exp(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = exp(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Ln(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = log(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Log10(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = log10(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Log2(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = log(*d) / log (2.0); - return &e->result_.double_val; -} - -void* MathFunctions::Log(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 2); - double* base = reinterpret_cast(e->children()[0]->GetValue(row)); - double* val = reinterpret_cast(e->children()[1]->GetValue(row)); - if (val == NULL || base == NULL) return NULL; - e->result_.double_val = log(*val) / log(*base); - return &e->result_.double_val; -} - -void* MathFunctions::Pow(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 2); - double* base = reinterpret_cast(e->children()[0]->GetValue(row)); - double* exp = reinterpret_cast(e->children()[1]->GetValue(row)); - if (exp == NULL || base == NULL) return NULL; - e->result_.double_val = pow(*base, *exp); - return &e->result_.double_val; -} - -void* MathFunctions::Sqrt(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - double* d = reinterpret_cast(e->children()[0]->GetValue(row)); - if (d == NULL) return NULL; - e->result_.double_val = sqrt(*d); - return &e->result_.double_val; -} - -void* MathFunctions::Rand(Expr* e, TupleRow* row) { - // Use e->result_.int_val as state for the random number generator. - // Cast is necessary, otherwise rand_r will complain. - e->result_.int_val = rand_r(reinterpret_cast(&e->result_.int_val)); - // Normalize to [0,1]. - e->result_.double_val = - static_cast(e->result_.int_val) / static_cast(RAND_MAX); - return &e->result_.double_val; -} - -void* MathFunctions::RandSeed(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - int32_t* seed = reinterpret_cast(e->children()[0]->GetValue(row)); - if (seed == NULL) return NULL; - // Use e->result_.bool_val to indicate whether initial seed has been set. - if (!e->result_.bool_val) { - // Set user-defined seed upon this first call. - e->result_.int_val = *seed; - e->result_.bool_val = true; +// Generates a UDF that always calls FN() on the input val and returns it. +#define ONE_ARG_MATH_FN(NAME, RET_TYPE, INPUT_TYPE, FN) \ + RET_TYPE MathFunctions::NAME(FunctionContext* ctx, const INPUT_TYPE& v) { \ + if (v.is_null) return RET_TYPE::null(); \ + return RET_TYPE(FN(v.val)); \ } - return Rand(e, row); + +ONE_ARG_MATH_FN(Abs, DoubleVal, DoubleVal, fabs); +ONE_ARG_MATH_FN(Sin, DoubleVal, DoubleVal, sin); +ONE_ARG_MATH_FN(Asin, DoubleVal, DoubleVal, asin); +ONE_ARG_MATH_FN(Cos, DoubleVal, DoubleVal, cos); +ONE_ARG_MATH_FN(Acos, DoubleVal, DoubleVal, acos); +ONE_ARG_MATH_FN(Tan, DoubleVal, DoubleVal, tan); +ONE_ARG_MATH_FN(Atan, DoubleVal, DoubleVal, atan); + +ONE_ARG_MATH_FN(Sqrt, DoubleVal, DoubleVal, sqrt); +ONE_ARG_MATH_FN(Ceil, BigIntVal, DoubleVal, ceil); +ONE_ARG_MATH_FN(Floor, BigIntVal, DoubleVal, floor); +ONE_ARG_MATH_FN(Ln, DoubleVal, DoubleVal, log); +ONE_ARG_MATH_FN(Log10, DoubleVal, DoubleVal, log10); +ONE_ARG_MATH_FN(Exp, DoubleVal, DoubleVal, exp); + +FloatVal MathFunctions::Sign(FunctionContext* ctx, const DoubleVal& v) { + if (v.is_null) return FloatVal::null(); + return FloatVal((v.val > 0) ? 1.0f : ((v.val < 0) ? -1.0f : 0.0f)); } -void* MathFunctions::Bin(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); +DoubleVal MathFunctions::Radians(FunctionContext* ctx, const DoubleVal& v) { + if (v.is_null) return v; + return DoubleVal(v.val * M_PI / 180.0); +} + +DoubleVal MathFunctions::Degrees(FunctionContext* ctx, const DoubleVal& v) { + if (v.is_null) return v; + return DoubleVal(v.val * 180.0 / M_PI); +} + +BigIntVal MathFunctions::Round(FunctionContext* ctx, const DoubleVal& v) { + if (v.is_null) return BigIntVal::null(); + return BigIntVal(static_cast(v.val + ((v.val < 0) ? -0.5 : 0.5))); +} + +DoubleVal MathFunctions::RoundUpTo(FunctionContext* ctx, const DoubleVal& v, + const IntVal& scale) { + if (v.is_null || scale.is_null) return DoubleVal::null(); + return DoubleVal(floor(v.val * pow(10.0, scale.val) + 0.5) / pow(10.0, scale.val)); +} + +DoubleVal MathFunctions::Log2(FunctionContext* ctx, const DoubleVal& v) { + if (v.is_null) return DoubleVal::null(); + return DoubleVal(log(v.val) / log(2.0)); +} + +DoubleVal MathFunctions::Log(FunctionContext* ctx, const DoubleVal& base, + const DoubleVal& v) { + if (base.is_null || v.is_null) return DoubleVal::null(); + return DoubleVal(log(v.val) / log(base.val)); +} + +DoubleVal MathFunctions::Pow(FunctionContext* ctx, const DoubleVal& base, + const DoubleVal& exp) { + if (base.is_null || exp.is_null) return DoubleVal::null(); + return DoubleVal(pow(base.val, exp.val)); +} + +void MathFunctions::RandPrepare( + FunctionContext* ctx, FunctionContext::FunctionStateScope scope) { + if (scope == FunctionContext::THREAD_LOCAL) { + uint32_t* seed = reinterpret_cast(ctx->Allocate(sizeof(uint32_t))); + ctx->SetFunctionState(scope, seed); + if (ctx->GetNumArgs() == 1) { + // This is a call to RandSeed, initialize the seed + // TODO: should we support non-constant seed? + if (!ctx->IsArgConstant(0)) { + ctx->SetError("Seed argument to rand() must be constant"); + return; + } + DCHECK_EQ(ctx->GetArgType(0)->type, FunctionContext::TYPE_BIGINT); + BigIntVal* seed_arg = static_cast(ctx->GetConstantArg(0)); + if (seed_arg->is_null) { + seed = NULL; + } else { + *seed = seed_arg->val; + } + } else { + // This is a call to Rand, initialize seed to 0 + // TODO: can we change this behavior? This is stupid. + *seed = 0; + } + } +} + +DoubleVal MathFunctions::Rand(FunctionContext* ctx) { + uint32_t* seed = + reinterpret_cast(ctx->GetFunctionState(FunctionContext::THREAD_LOCAL)); + DCHECK(seed != NULL); + *seed = rand_r(seed); + // Normalize to [0,1]. + return DoubleVal(static_cast(*seed) / RAND_MAX); +} + +DoubleVal MathFunctions::RandSeed(FunctionContext* ctx, const BigIntVal& seed) { + if (seed.is_null) return DoubleVal::null(); + return Rand(ctx); +} + +StringVal MathFunctions::Bin(FunctionContext* ctx, const BigIntVal& v) { + if (v.is_null) return StringVal::null(); // Cast to an unsigned integer because it is compiler dependent // whether the sign bit will be shifted like a regular bit. // (logical vs. arithmetic shift for signed numbers) - uint64_t* num = reinterpret_cast(e->children()[0]->GetValue(row)); - if (num == NULL) return NULL; - uint64_t n = *num; + uint64_t n = static_cast(v.val); const size_t max_bits = sizeof(uint64_t) * 8; char result[max_bits]; uint32_t index = max_bits; do { result[--index] = '0' + (n & 1); } while (n >>= 1); - StringValue val(result + index, max_bits - index); - // Copies the data in result. - e->result_.SetStringVal(val); - return &e->result_.string_val; + return AnyValUtil::FromBuffer(ctx, result + index, max_bits - index); } -void* MathFunctions::HexInt(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - int64_t* num = reinterpret_cast(e->children()[0]->GetValue(row)); - if (num == NULL) return NULL; +StringVal MathFunctions::HexInt(FunctionContext* ctx, const BigIntVal& v) { + if (v.is_null) return StringVal::null(); + // TODO: this is probably unreasonably slow stringstream ss; - ss << hex << uppercase << *num; - e->result_.SetStringVal(ss.str()); - return &e->result_.string_val; + ss << hex << uppercase << v.val; + return AnyValUtil::FromString(ctx, ss.str()); } -void* MathFunctions::HexString(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - StringValue* s = reinterpret_cast(e->children()[0]->GetValue(row)); - if (s == NULL) return NULL; +StringVal MathFunctions::HexString(FunctionContext* ctx, const StringVal& s) { + if (s.is_null) return StringVal::null(); stringstream ss; ss << hex << uppercase << setfill('0'); - for (int i = 0; i < s->len; ++i) { + for (int i = 0; i < s.len; ++i) { // setw is not sticky. stringstream only converts integral values, // so a cast to int is required, but only convert the least significant byte to hex. - ss << setw(2) << (static_cast(s->ptr[i]) & 0xFF); + ss << setw(2) << (static_cast(s.ptr[i]) & 0xFF); } - e->result_.SetStringVal(ss.str()); - return &e->result_.string_val; + return AnyValUtil::FromString(ctx, ss.str()); } -void* MathFunctions::Unhex(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - StringValue* s = reinterpret_cast(e->children()[0]->GetValue(row)); - if (s == NULL) return NULL; +StringVal MathFunctions::Unhex(FunctionContext* ctx, const StringVal& s) { + if (s.is_null) return StringVal::null(); // For uneven number of chars return empty string like Hive does. - if (s->len % 2 != 0) { - e->result_.string_val.len = 0; - e->result_.string_val.ptr = NULL; - return &e->result_.string_val; - } - int result_len = s->len / 2; + if (s.len % 2 != 0) return StringVal(); + + int result_len = s.len / 2; char result[result_len]; int res_index = 0; int s_index = 0; - while (s_index < s->len) { + while (s_index < s.len) { char c = 0; for (int j = 0; j < 2; ++j, ++s_index) { - switch(s->ptr[s_index]) { + switch(s.ptr[s_index]) { case '0': case '1': case '2': @@ -308,7 +202,7 @@ void* MathFunctions::Unhex(Expr* e, TupleRow* row) { case '7': case '8': case '9': - c += (s->ptr[s_index] - '0') * ((j == 0) ? 16 : 1); + c += (s.ptr[s_index] - '0') * ((j == 0) ? 16 : 1); break; case 'A': case 'B': @@ -317,7 +211,7 @@ void* MathFunctions::Unhex(Expr* e, TupleRow* row) { case 'E': case 'F': // Map to decimal values [10, 15] - c += (s->ptr[s_index] - 'A' + 10) * ((j == 0) ? 16 : 1); + c += (s.ptr[s_index] - 'A' + 10) * ((j == 0) ? 16 : 1); break; case 'a': case 'b': @@ -326,93 +220,73 @@ void* MathFunctions::Unhex(Expr* e, TupleRow* row) { case 'e': case 'f': // Map to decimal [10, 15] - c += (s->ptr[s_index] - 'a' + 10) * ((j == 0) ? 16 : 1); + c += (s.ptr[s_index] - 'a' + 10) * ((j == 0) ? 16 : 1); break; default: // Character not in hex alphabet, return empty string. - e->result_.string_val.len = 0; - e->result_.string_val.ptr = NULL; - return &e->result_.string_val; + return StringVal(); } } result[res_index] = c; ++res_index; } - StringValue val(result, result_len); - // Copies the data in result. - e->result_.SetStringVal(val); - return &e->result_.string_val; + return AnyValUtil::FromBuffer(ctx, result, result_len); } -void* MathFunctions::ConvInt(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 3); - int64_t* num = reinterpret_cast(e->children()[0]->GetValue(row)); - int8_t* src_base = reinterpret_cast(e->children()[1]->GetValue(row)); - int8_t* dest_base = reinterpret_cast(e->children()[2]->GetValue(row)); - if (num == NULL || src_base == NULL || dest_base == NULL) { - return NULL; - } +StringVal MathFunctions::ConvInt(FunctionContext* ctx, const BigIntVal& num, + const TinyIntVal& src_base, const TinyIntVal& dest_base) { + if (num.is_null || src_base.is_null || dest_base.is_null) return StringVal::null(); // As in MySQL and Hive, min base is 2 and max base is 36. // (36 is max base representable by alphanumeric chars) // If a negative target base is given, num should be interpreted in 2's complement. - if (abs(*src_base) < MIN_BASE || abs(*src_base) > MAX_BASE - || abs(*dest_base) < MIN_BASE || abs(*dest_base) > MAX_BASE) { + if (abs(src_base.val) < MIN_BASE || abs(src_base.val) > MAX_BASE + || abs(dest_base.val) < MIN_BASE || abs(dest_base.val) > MAX_BASE) { // Return NULL like Hive does. - return NULL; + return StringVal::null(); } - if (*src_base < 0 && *num >= 0) { - // Invalid input. - return NULL; - } - int64_t decimal_num = *num; - if (*src_base != 10) { + + // Invalid input. + if (src_base.val < 0 && num.val >= 0) return StringVal::null(); + int64_t decimal_num = num.val; + if (src_base.val != 10) { // Convert src_num representing a number in src_base but encoded in decimal // into its actual decimal number. - if (!DecimalInBaseToDecimal(*num, *src_base, &decimal_num)) { + if (!DecimalInBaseToDecimal(num.val, src_base.val, &decimal_num)) { // Handle overflow, setting decimal_num appropriately. - HandleParseResult(*dest_base, &decimal_num, StringParser::PARSE_OVERFLOW); + HandleParseResult(dest_base.val, &decimal_num, StringParser::PARSE_OVERFLOW); } } - DecimalToBase(decimal_num, *dest_base, &e->result_); - return &e->result_.string_val; + return DecimalToBase(ctx, decimal_num, dest_base.val); } -void* MathFunctions::ConvString(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 3); - StringValue* num_str = reinterpret_cast(e->children()[0]->GetValue(row)); - int8_t* src_base = reinterpret_cast(e->children()[1]->GetValue(row)); - int8_t* dest_base = reinterpret_cast(e->children()[2]->GetValue(row)); - if (num_str == NULL || src_base == NULL || dest_base == NULL) { - return NULL; - } +StringVal MathFunctions::ConvString(FunctionContext* ctx, const StringVal& num_str, + const TinyIntVal& src_base, const TinyIntVal& dest_base) { + if (num_str.is_null || src_base.is_null || dest_base.is_null) return StringVal::null(); // As in MySQL and Hive, min base is 2 and max base is 36. // (36 is max base representable by alphanumeric chars) // If a negative target base is given, num should be interpreted in 2's complement. - if (abs(*src_base) < MIN_BASE || abs(*src_base) > MAX_BASE - || abs(*dest_base) < MIN_BASE || abs(*dest_base) > MAX_BASE) { + if (abs(src_base.val) < MIN_BASE || abs(src_base.val) > MAX_BASE + || abs(dest_base.val) < MIN_BASE || abs(dest_base.val) > MAX_BASE) { // Return NULL like Hive does. - return NULL; + return StringVal::null(); } // Convert digits in num_str in src_base to decimal. StringParser::ParseResult parse_res; - int64_t decimal_num = StringParser::StringToInt(num_str->ptr, num_str->len, - *src_base, &parse_res); - if (*src_base < 0 && decimal_num >= 0) { + int64_t decimal_num = StringParser::StringToInt( + reinterpret_cast(num_str.ptr), num_str.len, src_base.val, &parse_res); + if (src_base.val < 0 && decimal_num >= 0) { // Invalid input. - return NULL; + return StringVal::null(); } - if (!HandleParseResult(*dest_base, &decimal_num, parse_res)) { + if (!HandleParseResult(dest_base.val, &decimal_num, parse_res)) { // Return 0 for invalid input strings like Hive does. - StringValue val(const_cast("0"), 1); - e->result_.SetStringVal(val); - return &e->result_.string_val; + return StringVal(reinterpret_cast(const_cast("0")), 1); } - DecimalToBase(decimal_num, *dest_base, &e->result_); - return &e->result_.string_val; + return DecimalToBase(ctx, decimal_num, dest_base.val); } -void MathFunctions::DecimalToBase(int64_t src_num, int8_t dest_base, - ExprValue* expr_val) { +StringVal MathFunctions::DecimalToBase(FunctionContext* ctx, int64_t src_num, + int8_t dest_base) { // Max number of digits of any base (base 2 gives max digits), plus sign. const size_t max_digits = sizeof(uint64_t) * 8 + 1; char buf[max_digits]; @@ -439,9 +313,7 @@ void MathFunctions::DecimalToBase(int64_t src_num, int8_t dest_base, buf[buf_index] = '-'; ++result_len; } - StringValue val(buf + max_digits - result_len, result_len); - // Copies the data in result. - expr_val->SetStringVal(val); + return AnyValUtil::FromBuffer(ctx, buf + max_digits - result_len, result_len); } bool MathFunctions::DecimalInBaseToDecimal(int64_t src_num, int8_t src_base, @@ -486,213 +358,195 @@ bool MathFunctions::HandleParseResult(int8_t dest_base, int64_t* num, return true; } -void* MathFunctions::PmodBigInt(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 2); - int64_t* a = reinterpret_cast(e->children()[0]->GetValue(row)); - int64_t* b = reinterpret_cast(e->children()[1]->GetValue(row)); - if (a == NULL || b == NULL) return NULL; - e->result_.bigint_val = ((*a % *b) + *b) % *b; - return &e->result_.bigint_val; +BigIntVal MathFunctions::PmodBigInt(FunctionContext* ctx, const BigIntVal& a, + const BigIntVal& b) { + if (a.is_null || b.is_null) return BigIntVal::null(); + return BigIntVal(((a.val % b.val) + b.val) % b.val); } -void* MathFunctions::PmodDouble(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 2); - double* a = reinterpret_cast(e->children()[0]->GetValue(row)); - double* b = reinterpret_cast(e->children()[1]->GetValue(row)); - if (a == NULL || b == NULL) return NULL; - e->result_.double_val = fmod(fmod(*a, *b) + *b, *b); - return &e->result_.double_val; +DoubleVal MathFunctions::PmodDouble(FunctionContext* ctx, const DoubleVal& a, + const DoubleVal& b) { + if (a.is_null || b.is_null) return DoubleVal::null(); + return DoubleVal(fmod(fmod(a.val, b.val) + b.val, b.val)); } -void* MathFunctions::FmodFloat(Expr* e, TupleRow* row) { - float* val1 = reinterpret_cast(e->children()[0]->GetValue(row)); - float* val2 = reinterpret_cast(e->children()[1]->GetValue(row)); - if (val1 == NULL || val2 == NULL || *val2 == 0) return NULL; - e->result_.float_val = fmodf(*val1, *val2); - return &e->result_.float_val; +FloatVal MathFunctions::FmodFloat(FunctionContext* ctx, const FloatVal& a, + const FloatVal& b) { + if (a.is_null || b.is_null || b.val == 0) return FloatVal::null(); + return FloatVal(fmodf(a.val, b.val)); } -void* MathFunctions::FmodDouble(Expr* e, TupleRow* row) { - double* val1 = reinterpret_cast(e->children()[0]->GetValue(row)); - double* val2 = reinterpret_cast(e->children()[1]->GetValue(row)); - if (val1 == NULL || val2 == NULL || *val2 == 0) return NULL; - e->result_.double_val = fmod(*val1, *val2); - return &e->result_.double_val; +DoubleVal MathFunctions::FmodDouble(FunctionContext* ctx, const DoubleVal& a, + const DoubleVal& b) { + if (a.is_null || b.is_null || b.val == 0) return DoubleVal::null(); + return DoubleVal(fmod(a.val, b.val)); } -void* MathFunctions::Positive(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - return e->children()[0]->GetValue(row); +template T MathFunctions::Positive(FunctionContext* ctx, const T& val) { + return val; } -template void* MathFunctions::Negative(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - T* i = reinterpret_cast(e->children()[0]->GetValue(row)); - if (i == NULL) return NULL; - return e->result_.Set(-*i); +template T MathFunctions::Negative(FunctionContext* ctx, const T& val) { + if (val.is_null) return val; + return T(-val.val); } -void* MathFunctions::NegativeDecimal(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 1); - void* i = e->children()[0]->GetValue(row); - if (i == NULL) return NULL; - switch (e->type().GetByteSize()) { - case 4: - return e->result_.Set(-*reinterpret_cast(i)); - case 8: - return e->result_.Set(-*reinterpret_cast(i)); - case 16: - return e->result_.Set(-*reinterpret_cast(i)); - default: - DCHECK(false); - return NULL; +template <> +DecimalVal MathFunctions::Negative(FunctionContext* ctx, const DecimalVal& val) { + if (val.is_null) return val; + return DecimalVal(-val.val16); +} + +BigIntVal MathFunctions::QuotientDouble(FunctionContext* ctx, const DoubleVal& x, + const DoubleVal& y) { + if (x.is_null || y.is_null || static_cast(y.val) == 0) { + return BigIntVal::null(); } + return BigIntVal(static_cast(x.val) / static_cast(y.val)); } -void* MathFunctions::QuotientDouble(Expr* e, TupleRow* row) { - DCHECK_EQ(e->GetNumChildren(), 2); - Expr* op1 = e->children()[0]; - double* val1 = reinterpret_cast(op1->GetValue(row)); - Expr* op2 = e->children()[1]; - double* val2 = reinterpret_cast(op2->GetValue(row)); - if (val1 == NULL || val2 == NULL || static_cast(*val2) == 0) return NULL; - e->result_.bigint_val = (static_cast(*val1) / static_cast(*val2)); - return &e->result_.bigint_val; +BigIntVal MathFunctions::QuotientBigInt(FunctionContext* ctx, const BigIntVal& x, + const BigIntVal& y) { + return Operators::Int_divide_BigIntVal_BigIntVal(ctx, x, y); } -// TODO(skye): replace this with ComputeFunctions::Int_divide_bigint_bigint when -// converting math functions to UDF interface -void* MathFunctions::QuotientBigInt(Expr* e, TupleRow* row) { - Expr* op1 = e->children()[0]; - int64_t* val1 = reinterpret_cast(op1->GetValue(row)); - Expr* op2 = e->children()[1]; - int64_t* val2 = reinterpret_cast(op2->GetValue(row)); - if (val1 == NULL || val2 == NULL || *val2 == 0) return NULL; - e->result_.bigint_val = (*val1 / *val2); - return &e->result_.bigint_val; -} - -template -void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row) { - DCHECK_GT(e->GetNumChildren(), 0); - T* val = reinterpret_cast(e->children()[0]->GetValue(row)); - if (val == NULL) return NULL; - T result_val = *val; - int num_children = e->GetNumChildren(); - for (int i = 1; i < num_children; ++i) { - val = reinterpret_cast(e->children()[i]->GetValue(row)); - if (val == NULL) return NULL; +template VAL_TYPE MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const VAL_TYPE* args) { + DCHECK_GT(num_args, 0); + if (args[0].is_null) return VAL_TYPE::null(); + int result_idx = 0; + for (int i = 1; i < num_args; ++i) { + if (args[i].is_null) return VAL_TYPE::null(); if (ISLEAST) { - if (*val < result_val) result_val = *val; + if (args[i].val < args[result_idx].val) result_idx = i; } else { - if (*val > result_val) result_val = *val; + if (args[i].val > args[result_idx].val) result_idx = i; } } - return e->result_.Set(result_val); + return VAL_TYPE(args[result_idx].val); } -template -void* MathFunctions::LeastGreatestString(Expr* e, TupleRow* row) { - DCHECK_GT(e->GetNumChildren(), 0); - StringValue* val = - reinterpret_cast(e->children()[0]->GetValue(row)); - if (val == NULL) return NULL; - StringValue* result_val = val; - int num_children = e->GetNumChildren(); - for (int i = 1; i < num_children; ++i) { - val = reinterpret_cast(e->children()[i]->GetValue(row)); - if (val == NULL) return NULL; +template StringVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const StringVal* args) { + DCHECK_GT(num_args, 0); + if (args[0].is_null) return StringVal::null(); + StringValue result_val = StringValue::FromStringVal(args[0]); + for (int i = 1; i < num_args; ++i) { + if (args[i].is_null) return StringVal::null(); + StringValue val = StringValue::FromStringVal(args[i]); if (ISLEAST) { - if (val->Compare(*result_val) < 0) result_val = val; + if (val < result_val) result_val = val; } else { - if (val->Compare(*result_val) > 0) result_val = val; + if (val > result_val) result_val = val; } } - e->result_.string_val.ptr = result_val->ptr; - e->result_.string_val.len = result_val->len; - return &e->result_.string_val; + StringVal result; + result_val.ToStringVal(&result); + return result; } -template -void* MathFunctions::LeastGreatestDecimal(Expr* e, TupleRow* row) { - DCHECK_GT(e->GetNumChildren(), 0); - void* first_val = e->children()[0]->GetValue(row); - if (first_val == NULL) return NULL; - int num_children = e->GetNumChildren(); - switch (e->type().GetByteSize()) { - case 4: { - Decimal4Value* val = reinterpret_cast(first_val); - Decimal4Value result_val = *val; - for (int i = 1; i < num_children; ++i) { - val = reinterpret_cast(e->children()[i]->GetValue(row)); - if (val == NULL) return NULL; - if (ISLEAST) { - if (*val < result_val) result_val = *val; - } else { - if (*val > result_val) result_val = *val; - } - } - return e->result_.Set(result_val); +template TimestampVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const TimestampVal* args) { + DCHECK_GT(num_args, 0); + if (args[0].is_null) return TimestampVal::null(); + TimestampValue result_val = TimestampValue::FromTimestampVal(args[0]); + for (int i = 1; i < num_args; ++i) { + if (args[i].is_null) return TimestampVal::null(); + TimestampValue val = TimestampValue::FromTimestampVal(args[i]); + if (ISLEAST) { + if (val < result_val) result_val = val; + } else { + if (val > result_val) result_val = val; } - case 8: { - Decimal8Value* val = reinterpret_cast(first_val); - Decimal8Value result_val = *val; - for (int i = 1; i < num_children; ++i) { - val = reinterpret_cast(e->children()[i]->GetValue(row)); - if (val == NULL) return NULL; - if (ISLEAST) { - if (*val < result_val) result_val = *val; - } else { - if (*val > result_val) result_val = *val; - } - } - return e->result_.Set(result_val); - } - case 16: { - Decimal16Value* val = reinterpret_cast(first_val); - Decimal16Value result_val = *val; - for (int i = 1; i < num_children; ++i) { - val = reinterpret_cast(e->children()[i]->GetValue(row)); - if (val == NULL) return NULL; - if (ISLEAST) { - if (*val < result_val) result_val = *val; - } else { - if (*val > result_val) result_val = *val; - } - } - return e->result_.Set(result_val); - } - default: - DCHECK(false); - return NULL; } + TimestampVal result; + result_val.ToTimestampVal(&result); + return result; } -template void* MathFunctions::Negative(Expr* e, TupleRow* row); -template void* MathFunctions::Negative(Expr* e, TupleRow* row); -template void* MathFunctions::Negative(Expr* e, TupleRow* row); -template void* MathFunctions::Negative(Expr* e, TupleRow* row); -template void* MathFunctions::Negative(Expr* e, TupleRow* row); -template void* MathFunctions::Negative(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatestString(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatest(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatestString(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatestDecimal(Expr* e, TupleRow* row); -template void* MathFunctions::LeastGreatestDecimal(Expr* e, TupleRow* row); - - +template DecimalVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const DecimalVal* args) { + DCHECK_GT(num_args, 0); + if (args[0].is_null) return DecimalVal::null(); + DecimalVal result_val = args[0]; + for (int i = 1; i < num_args; ++i) { + if (args[i].is_null) return DecimalVal::null(); + if (ISLEAST) { + if (args[i].val16 < result_val.val16) result_val = args[i]; + } else { + if (args[i].val16 > result_val.val16) result_val = args[i]; + } + } + return result_val; } +template TinyIntVal MathFunctions::Positive( + FunctionContext* ctx, const TinyIntVal& val); +template SmallIntVal MathFunctions::Positive( + FunctionContext* ctx, const SmallIntVal& val); +template IntVal MathFunctions::Positive( + FunctionContext* ctx, const IntVal& val); +template BigIntVal MathFunctions::Positive( + FunctionContext* ctx, const BigIntVal& val); +template FloatVal MathFunctions::Positive( + FunctionContext* ctx, const FloatVal& val); +template DoubleVal MathFunctions::Positive( + FunctionContext* ctx, const DoubleVal& val); +template DecimalVal MathFunctions::Positive( + FunctionContext* ctx, const DecimalVal& val); + +template TinyIntVal MathFunctions::Negative( + FunctionContext* ctx, const TinyIntVal& val); +template SmallIntVal MathFunctions::Negative( + FunctionContext* ctx, const SmallIntVal& val); +template IntVal MathFunctions::Negative( + FunctionContext* ctx, const IntVal& val); +template BigIntVal MathFunctions::Negative( + FunctionContext* ctx, const BigIntVal& val); +template FloatVal MathFunctions::Negative( + FunctionContext* ctx, const FloatVal& val); +template DoubleVal MathFunctions::Negative( + FunctionContext* ctx, const DoubleVal& val); + +template TinyIntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const TinyIntVal* args); +template SmallIntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const SmallIntVal* args); +template IntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const IntVal* args); +template BigIntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const BigIntVal* args); +template FloatVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const FloatVal* args); +template DoubleVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const DoubleVal* args); + +template TinyIntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const TinyIntVal* args); +template SmallIntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const SmallIntVal* args); +template IntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const IntVal* args); +template BigIntVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const BigIntVal* args); +template FloatVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const FloatVal* args); +template DoubleVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const DoubleVal* args); + +template StringVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const StringVal* args); +template StringVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const StringVal* args); + +template TimestampVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const TimestampVal* args); +template TimestampVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const TimestampVal* args); + +template DecimalVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const DecimalVal* args); +template DecimalVal MathFunctions::LeastGreatest( + FunctionContext* ctx, int num_args, const DecimalVal* args); + +} diff --git a/be/src/exprs/math-functions.h b/be/src/exprs/math-functions.h index a681cfc13..5bf20a22f 100644 --- a/be/src/exprs/math-functions.h +++ b/be/src/exprs/math-functions.h @@ -19,6 +19,9 @@ #include // For StringParser::ParseResult #include "util/string-parser.h" +#include "udf/udf.h" + +using namespace impala_udf; namespace impala { @@ -28,58 +31,70 @@ class TupleRow; class MathFunctions { public: - static void* Pi(Expr* e, TupleRow* row); - static void* E(Expr* e, TupleRow* row); - static void* Abs(Expr* e, TupleRow* row); - static void* Sign(Expr* e, TupleRow* row); - static void* Sin(Expr* e, TupleRow* row); - static void* Asin(Expr* e, TupleRow* row); - static void* Cos(Expr* e, TupleRow* row); - static void* Acos(Expr* e, TupleRow* row); - static void* Tan(Expr* e, TupleRow* row); - static void* Atan(Expr* e, TupleRow* row); - static void* Radians(Expr* e, TupleRow* row); - static void* Degrees(Expr* e, TupleRow* row); - static void* Ceil(Expr* e, TupleRow* row); - static void* Floor(Expr* e, TupleRow* row); - static void* Round(Expr* e, TupleRow* row); - static void* RoundUpTo(Expr* e, TupleRow* row); - static void* Exp(Expr* e, TupleRow* row); - static void* Ln(Expr* e, TupleRow* row); - static void* Log10(Expr* e, TupleRow* row); - static void* Log2(Expr* e, TupleRow* row); - static void* Log(Expr* e, TupleRow* row); - static void* Pow(Expr* e, TupleRow* row); - static void* Sqrt(Expr* e, TupleRow* row); - static void* Rand(Expr* e, TupleRow* row); - static void* RandSeed(Expr* e, TupleRow* row); - static void* Bin(Expr* e, TupleRow* row); - static void* HexInt(Expr* e, TupleRow* row); - static void* HexString(Expr* e, TupleRow* row); - static void* Unhex(Expr* e, TupleRow* row); - static void* ConvInt(Expr* e, TupleRow* row); - static void* ConvString(Expr* e, TupleRow* row); - static void* PmodBigInt(Expr* e, TupleRow* row); - static void* PmodDouble(Expr* e, TupleRow* row); - static void* FmodFloat(Expr* e, TupleRow* row); - static void* FmodDouble(Expr* e, TupleRow* row); - static void* QuotientDouble(Expr* e, TupleRow* row); - static void* QuotientBigInt(Expr* e, TupleRow* row); - static void* Positive(Expr* e, TupleRow* row); - template static void* Negative(Expr* e, TupleRow* row); - static void* NegativeDecimal(Expr* e, TupleRow* row); - template static void* LeastGreatest(Expr* e, TupleRow* row); - template static void* LeastGreatestString(Expr* e, TupleRow* row); - template static void* LeastGreatestDecimal(Expr* e, TupleRow* row); + static DoubleVal Pi(FunctionContext*); + static DoubleVal E(FunctionContext*); + static DoubleVal Abs(FunctionContext*, const DoubleVal&); + static DoubleVal Sin(FunctionContext*, const DoubleVal&); + static DoubleVal Asin(FunctionContext*, const DoubleVal&); + static DoubleVal Cos(FunctionContext*, const DoubleVal&); + static DoubleVal Acos(FunctionContext*, const DoubleVal&); + static DoubleVal Tan(FunctionContext*, const DoubleVal&); + static DoubleVal Atan(FunctionContext*, const DoubleVal&); + static DoubleVal Sqrt(FunctionContext*, const DoubleVal&); + static DoubleVal Exp(FunctionContext*, const DoubleVal&); + static BigIntVal Ceil(FunctionContext*, const DoubleVal&); + static BigIntVal Floor(FunctionContext*, const DoubleVal&); + static DoubleVal Ln(FunctionContext*, const DoubleVal&); + static DoubleVal Log10(FunctionContext*, const DoubleVal&); + static FloatVal Sign(FunctionContext*, const DoubleVal&); + static DoubleVal Radians(FunctionContext*, const DoubleVal&); + static DoubleVal Degrees(FunctionContext*, const DoubleVal&); + static BigIntVal Round(FunctionContext*, const DoubleVal&); + static DoubleVal RoundUpTo(FunctionContext*, const DoubleVal&, const IntVal&); + static DoubleVal Log2(FunctionContext*, const DoubleVal&); + static DoubleVal Log(FunctionContext*, const DoubleVal& base, const DoubleVal& val); + static DoubleVal Pow(FunctionContext*, const DoubleVal& base, const DoubleVal& val); + + // Used for both Rand() and RandSeed() + static void RandPrepare(FunctionContext*, FunctionContext::FunctionStateScope); + static DoubleVal Rand(FunctionContext*); + static DoubleVal RandSeed(FunctionContext*, const BigIntVal& seed); + + static StringVal Bin(FunctionContext*, const BigIntVal&); + static StringVal HexInt(FunctionContext*, const BigIntVal&); + static StringVal HexString(FunctionContext*, const StringVal&); + static StringVal Unhex(FunctionContext*, const StringVal&); + static StringVal ConvInt(FunctionContext*, const BigIntVal& n, + const TinyIntVal& src_base, const TinyIntVal& dst_base); + static StringVal ConvString(FunctionContext*, const StringVal& s, + const TinyIntVal& src_base, const TinyIntVal& dst_base); + static BigIntVal PmodBigInt(FunctionContext*, const BigIntVal&, const BigIntVal&); + static DoubleVal PmodDouble(FunctionContext*, const DoubleVal&, const DoubleVal&); + static FloatVal FmodFloat(FunctionContext*, const FloatVal&, const FloatVal&); + static DoubleVal FmodDouble(FunctionContext*, const DoubleVal&, const DoubleVal&); + + template static T Positive(FunctionContext*, const T&); + template static T Negative(FunctionContext*, const T&); + + static BigIntVal QuotientDouble(FunctionContext*, const DoubleVal&, const DoubleVal&); + static BigIntVal QuotientBigInt(FunctionContext*, const BigIntVal&, const BigIntVal&); + + template + static VAL_TYPE LeastGreatest(FunctionContext*, int num_args, const VAL_TYPE* args); + template static StringVal LeastGreatest( + FunctionContext*, int num_args, const StringVal* args); + template static TimestampVal LeastGreatest( + FunctionContext*, int num_args, const TimestampVal* args); + template static DecimalVal LeastGreatest( + FunctionContext*, int num_args, const DecimalVal* args); private: static const int32_t MIN_BASE = 2; static const int32_t MAX_BASE = 36; static const char* ALPHANUMERIC_CHARS; - // Converts src_num in decimal to dest_base, - // and fills expr_val.string_val with the result. - static void DecimalToBase(int64_t src_num, int8_t dest_base, ExprValue* expr_val); + // Converts src_num in decimal to dest_base. + static StringVal DecimalToBase(FunctionContext*, int64_t src_num, int8_t dest_base); // Converts src_num representing a number in src_base but encoded in decimal // into its actual decimal number. diff --git a/be/src/udf/udf.cc b/be/src/udf/udf.cc index 73b432ef9..94e32ab32 100644 --- a/be/src/udf/udf.cc +++ b/be/src/udf/udf.cc @@ -366,6 +366,10 @@ const FunctionContext::TypeDesc* FunctionContext::GetArgType(int arg_idx) const return &impl_->arg_types_[arg_idx]; } +int FunctionContext::GetNumArgs() const { + return impl_->arg_types_.size(); +} + const FunctionContext::TypeDesc& FunctionContext::GetReturnType() const { return impl_->return_type_; } diff --git a/be/src/udf/udf.h b/be/src/udf/udf.h index e3bfc7210..6cdac43c5 100644 --- a/be/src/udf/udf.h +++ b/be/src/udf/udf.h @@ -162,6 +162,10 @@ class FunctionContext { // return type of the UDA (e.g., the type returned by the finalize function). const TypeDesc& GetReturnType() const; + // Returns the number of arguments to this function (not including the FunctionContext* + // argument). + int GetNumArgs() const; + // Returns the type information for the arg_idx-th argument (0-indexed, not including // the FunctionContext* argument). Returns NULL if arg_idx is invalid. const TypeDesc* GetArgType(int arg_idx) const; diff --git a/common/function-registry/impala_functions.py b/common/function-registry/impala_functions.py index 1885382e8..88baec8d7 100755 --- a/common/function-registry/impala_functions.py +++ b/common/function-registry/impala_functions.py @@ -53,99 +53,6 @@ def symbol(class_name, fn_name, templated_type = None): # # The symbol can be empty for functions that are not yet implemented. functions = [ - # Math builtin functions - [['pi'], 'DOUBLE', [], symbol('MathFunctions', 'Pi')], - [['e'], 'DOUBLE', [], symbol('MathFunctions', 'E')], - [['abs'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Abs')], - [['sign'], 'FLOAT', ['DOUBLE'], symbol('MathFunctions', 'Sign')], - [['sin'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Sin')], - [['asin'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Asin')], - [['cos'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Cos')], - [['acos'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Acos')], - [['tan'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Tan')], - [['atan'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Atan')], - [['radians'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Radians')], - [['degrees'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Degrees')], - [['ceil', 'ceiling'], 'BIGINT', ['DOUBLE'], symbol('MathFunctions', 'Ceil')], - [['floor'], 'BIGINT', ['DOUBLE'], symbol('MathFunctions', 'Floor')], - [['round'], 'BIGINT', ['DOUBLE'], symbol('MathFunctions', 'Round')], - [['round'], 'DOUBLE', ['DOUBLE', 'INT'], symbol('MathFunctions', 'RoundUpTo')], - [['exp'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Exp')], - [['ln'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Ln')], - [['log10'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Log10')], - [['log2'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Log2')], - [['log'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], symbol('MathFunctions', 'Log')], - [['pow', 'power'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], symbol('MathFunctions', 'Pow')], - [['sqrt'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Sqrt')], - [['rand'], 'DOUBLE', [], symbol('MathFunctions', 'Rand')], - [['rand'], 'DOUBLE', ['INT'], symbol('MathFunctions', 'RandSeed')], - [['bin'], 'STRING', ['BIGINT'], symbol('MathFunctions', 'Bin')], - [['hex'], 'STRING', ['BIGINT'], symbol('MathFunctions', 'HexInt')], - [['hex'], 'STRING', ['STRING'], symbol('MathFunctions', 'HexString')], - [['unhex'], 'STRING', ['STRING'], symbol('MathFunctions', 'Unhex')], - [['conv'], 'STRING', ['BIGINT', 'TINYINT', 'TINYINT'], - symbol('MathFunctions', 'ConvInt')], - [['conv'], 'STRING', ['STRING', 'TINYINT', 'TINYINT'], - symbol('MathFunctions', 'ConvString')], - [['pmod'], 'BIGINT', ['BIGINT', 'BIGINT'], symbol('MathFunctions', 'PmodBigInt')], - [['pmod'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], symbol('MathFunctions', 'PmodDouble')], - [['fmod'], 'FLOAT', ['FLOAT', 'FLOAT'], symbol('MathFunctions', 'FmodFloat')], - [['fmod'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], symbol('MathFunctions', 'FmodDouble')], - [['positive'], 'TINYINT', ['TINYINT'], symbol('MathFunctions', 'Positive')], - [['positive'], 'SMALLINT', ['SMALLINT'], symbol('MathFunctions', 'Positive')], - [['positive'], 'INT', ['INT'], symbol('MathFunctions', 'Positive')], - [['positive'], 'BIGINT', ['BIGINT'], symbol('MathFunctions', 'Positive')], - [['positive'], 'FLOAT', ['FLOAT'], symbol('MathFunctions', 'Positive')], - [['positive'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Positive')], - [['positive'], 'DECIMAL', ['DECIMAL'], symbol('MathFunctions', 'Positive')], - [['negative'], 'TINYINT', ['TINYINT'], symbol('MathFunctions', 'Negative', 'int8_t')], - [['negative'], 'SMALLINT', ['SMALLINT'], symbol('MathFunctions', 'Negative', 'int16_t')], - [['negative'], 'INT', ['INT'], symbol('MathFunctions', 'Negative', 'int32_t')], - [['negative'], 'BIGINT', ['BIGINT'], symbol('MathFunctions', 'Negative', 'int64_t')], - [['negative'], 'FLOAT', ['FLOAT'], symbol('MathFunctions', 'Negative', 'float')], - [['negative'], 'DOUBLE', ['DOUBLE'], symbol('MathFunctions', 'Negative', 'double')], - [['negative'], 'DECIMAL', ['DECIMAL'], symbol('MathFunctions', 'NegativeDecimal')], - [['quotient'], 'BIGINT', ['BIGINT', 'BIGINT'], - symbol('MathFunctions', 'QuotientBigInt')], - [['quotient'], 'BIGINT', ['DOUBLE', 'DOUBLE'], - symbol('MathFunctions', 'QuotientDouble')], - [['least'], 'TINYINT', ['TINYINT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIaLb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'SMALLINT', ['SMALLINT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIsLb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'INT', ['INT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIiLb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'BIGINT', ['BIGINT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIlLb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'FLOAT', ['FLOAT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIfLb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'DOUBLE', ['DOUBLE', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIdLb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'TIMESTAMP', ['TIMESTAMP', '...'], - '_ZN6impala13MathFunctions13LeastGreatestINS_14TimestampValueELb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'STRING', ['STRING', '...'], - '_ZN6impala13MathFunctions19LeastGreatestStringILb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['least'], 'DECIMAL', ['DECIMAL', '...'], - '_ZN6impala13MathFunctions20LeastGreatestDecimalILb1EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'TINYINT', ['TINYINT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIaLb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'SMALLINT', ['SMALLINT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIsLb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'INT', ['INT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIiLb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'BIGINT', ['BIGINT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIlLb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'FLOAT', ['FLOAT', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIfLb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'DOUBLE', ['DOUBLE', '...'], - '_ZN6impala13MathFunctions13LeastGreatestIdLb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'TIMESTAMP', ['TIMESTAMP', '...'], - '_ZN6impala13MathFunctions13LeastGreatestINS_14TimestampValueELb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'STRING', ['STRING', '...'], - '_ZN6impala13MathFunctions19LeastGreatestStringILb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - [['greatest'], 'DECIMAL', ['DECIMAL', '...'], - '_ZN6impala13MathFunctions20LeastGreatestDecimalILb0EEEPvPNS_4ExprEPNS_8TupleRowE'], - # String builtin functions [['substr', 'substring'], 'STRING', ['STRING', 'INT'], symbol('StringFunctions', 'Substring', 'int32_t')], @@ -519,6 +426,115 @@ udf_functions = [ '_ZN6impala18TimestampFunctions20UnixAndFromUnixCloseEPN10impala_udf15FunctionContextENS2_18FunctionStateScopeE'], [['now', 'current_timestamp'], 'TIMESTAMP', [], '_ZN6impala18TimestampFunctions3NowEPN10impala_udf15FunctionContextE'], + # Math builtin functions + [['pi'], 'DOUBLE', [], 'impala::MathFunctions::Pi'], + [['e'], 'DOUBLE', [], 'impala::MathFunctions::E'], + [['abs'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Abs'], + [['sign'], 'FLOAT', ['DOUBLE'], 'impala::MathFunctions::Sign'], + [['sin'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Sin'], + [['asin'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Asin'], + [['cos'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Cos'], + [['acos'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Acos'], + [['tan'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Tan'], + [['atan'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Atan'], + [['radians'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Radians'], + [['degrees'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Degrees'], + [['ceil', 'ceiling'], 'BIGINT', ['DOUBLE'], 'impala::MathFunctions::Ceil'], + [['floor'], 'BIGINT', ['DOUBLE'], 'impala::MathFunctions::Floor'], + [['round'], 'BIGINT', ['DOUBLE'], 'impala::MathFunctions::Round'], + [['round'], 'DOUBLE', ['DOUBLE', 'INT'], 'impala::MathFunctions::RoundUpTo'], + [['exp'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Exp'], + [['ln'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Ln'], + [['log10'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Log10'], + [['log2'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Log2'], + [['log'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], 'impala::MathFunctions::Log'], + [['pow', 'power'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], 'impala::MathFunctions::Pow'], + [['sqrt'], 'DOUBLE', ['DOUBLE'], 'impala::MathFunctions::Sqrt'], + [['rand'], 'DOUBLE', [], 'impala::MathFunctions::Rand', + '_ZN6impala13MathFunctions11RandPrepareEPN10impala_udf15FunctionContextENS2_18FunctionStateScopeE'], + [['rand'], 'DOUBLE', ['BIGINT'], 'impala::MathFunctions::RandSeed', + '_ZN6impala13MathFunctions11RandPrepareEPN10impala_udf15FunctionContextENS2_18FunctionStateScopeE'], + [['bin'], 'STRING', ['BIGINT'], 'impala::MathFunctions::Bin'], + [['hex'], 'STRING', ['BIGINT'], 'impala::MathFunctions::HexInt'], + [['hex'], 'STRING', ['STRING'], 'impala::MathFunctions::HexString'], + [['unhex'], 'STRING', ['STRING'], 'impala::MathFunctions::Unhex'], + [['conv'], 'STRING', ['BIGINT', 'TINYINT', 'TINYINT'], + 'impala::MathFunctions::ConvInt'], + [['conv'], 'STRING', ['STRING', 'TINYINT', 'TINYINT'], + 'impala::MathFunctions::ConvString'], + [['pmod'], 'BIGINT', ['BIGINT', 'BIGINT'], 'impala::MathFunctions::PmodBigInt'], + [['pmod'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], 'impala::MathFunctions::PmodDouble'], + [['fmod'], 'FLOAT', ['FLOAT', 'FLOAT'], 'impala::MathFunctions::FmodFloat'], + [['fmod'], 'DOUBLE', ['DOUBLE', 'DOUBLE'], 'impala::MathFunctions::FmodDouble'], + [['positive'], 'TINYINT', ['TINYINT'], + '_ZN6impala13MathFunctions8PositiveIN10impala_udf10TinyIntValEEET_PNS2_15FunctionContextERKS4_'], + [['positive'], 'SMALLINT', ['SMALLINT'], + '_ZN6impala13MathFunctions8PositiveIN10impala_udf11SmallIntValEEET_PNS2_15FunctionContextERKS4_'], + [['positive'], 'INT', ['INT'], + '_ZN6impala13MathFunctions8PositiveIN10impala_udf6IntValEEET_PNS2_15FunctionContextERKS4_'], + [['positive'], 'BIGINT', ['BIGINT'], + '_ZN6impala13MathFunctions8PositiveIN10impala_udf9BigIntValEEET_PNS2_15FunctionContextERKS4_'], + [['positive'], 'FLOAT', ['FLOAT'], + '_ZN6impala13MathFunctions8PositiveIN10impala_udf8FloatValEEET_PNS2_15FunctionContextERKS4_'], + [['positive'], 'DOUBLE', ['DOUBLE'], + '_ZN6impala13MathFunctions8PositiveIN10impala_udf9DoubleValEEET_PNS2_15FunctionContextERKS4_'], + [['positive'], 'DECIMAL', ['DECIMAL'], + '_ZN6impala13MathFunctions8PositiveIN10impala_udf10DecimalValEEET_PNS2_15FunctionContextERKS4_'], + [['negative'], 'TINYINT', ['TINYINT'], + '_ZN6impala13MathFunctions8NegativeIN10impala_udf10TinyIntValEEET_PNS2_15FunctionContextERKS4_'], + [['negative'], 'SMALLINT', ['SMALLINT'], + '_ZN6impala13MathFunctions8NegativeIN10impala_udf11SmallIntValEEET_PNS2_15FunctionContextERKS4_'], + [['negative'], 'INT', ['INT'], + '_ZN6impala13MathFunctions8NegativeIN10impala_udf6IntValEEET_PNS2_15FunctionContextERKS4_'], + [['negative'], 'BIGINT', ['BIGINT'], + '_ZN6impala13MathFunctions8NegativeIN10impala_udf9BigIntValEEET_PNS2_15FunctionContextERKS4_'], + [['negative'], 'FLOAT', ['FLOAT'], + '_ZN6impala13MathFunctions8NegativeIN10impala_udf8FloatValEEET_PNS2_15FunctionContextERKS4_'], + [['negative'], 'DOUBLE', ['DOUBLE'], + '_ZN6impala13MathFunctions8NegativeIN10impala_udf9DoubleValEEET_PNS2_15FunctionContextERKS4_'], + [['negative'], 'DECIMAL', ['DECIMAL'], + '_ZN6impala13MathFunctions8NegativeIN10impala_udf10DecimalValEEET_PNS2_15FunctionContextERKS4_'], + [['quotient'], 'BIGINT', ['BIGINT', 'BIGINT'], + 'impala::MathFunctions::QuotientBigInt'], + [['quotient'], 'BIGINT', ['DOUBLE', 'DOUBLE'], + 'impala::MathFunctions::QuotientDouble'], + [['least'], 'TINYINT', ['TINYINT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf10TinyIntValELb1EEET_PNS2_15FunctionContextEiPKS4_'], + [['least'], 'SMALLINT', ['SMALLINT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf11SmallIntValELb1EEET_PNS2_15FunctionContextEiPKS4_'], + [['least'], 'INT', ['INT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf6IntValELb1EEET_PNS2_15FunctionContextEiPKS4_'], + [['least'], 'BIGINT', ['BIGINT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf9BigIntValELb1EEET_PNS2_15FunctionContextEiPKS4_'], + [['least'], 'FLOAT', ['FLOAT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf8FloatValELb1EEET_PNS2_15FunctionContextEiPKS4_'], + [['least'], 'DOUBLE', ['DOUBLE', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf9DoubleValELb1EEET_PNS2_15FunctionContextEiPKS4_'], + [['least'], 'TIMESTAMP', ['TIMESTAMP', '...'], + '_ZN6impala13MathFunctions13LeastGreatestILb1EEEN10impala_udf12TimestampValEPNS2_15FunctionContextEiPKS3_'], + [['least'], 'STRING', ['STRING', '...'], + '_ZN6impala13MathFunctions13LeastGreatestILb1EEEN10impala_udf9StringValEPNS2_15FunctionContextEiPKS3_'], + [['least'], 'DECIMAL', ['DECIMAL', '...'], + '_ZN6impala13MathFunctions13LeastGreatestILb1EEEN10impala_udf10DecimalValEPNS2_15FunctionContextEiPKS3_'], + [['greatest'], 'TINYINT', ['TINYINT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf10TinyIntValELb0EEET_PNS2_15FunctionContextEiPKS4_'], + [['greatest'], 'SMALLINT', ['SMALLINT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf11SmallIntValELb0EEET_PNS2_15FunctionContextEiPKS4_'], + [['greatest'], 'INT', ['INT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf6IntValELb0EEET_PNS2_15FunctionContextEiPKS4_'], + [['greatest'], 'BIGINT', ['BIGINT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf9BigIntValELb0EEET_PNS2_15FunctionContextEiPKS4_'], + [['greatest'], 'FLOAT', ['FLOAT', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf8FloatValELb0EEET_PNS2_15FunctionContextEiPKS4_'], + [['greatest'], 'DOUBLE', ['DOUBLE', '...'], + '_ZN6impala13MathFunctions13LeastGreatestIN10impala_udf9DoubleValELb0EEET_PNS2_15FunctionContextEiPKS4_'], + [['greatest'], 'TIMESTAMP', ['TIMESTAMP', '...'], + '_ZN6impala13MathFunctions13LeastGreatestILb0EEEN10impala_udf12TimestampValEPNS2_15FunctionContextEiPKS3_'], + [['greatest'], 'STRING', ['STRING', '...'], + '_ZN6impala13MathFunctions13LeastGreatestILb0EEEN10impala_udf9StringValEPNS2_15FunctionContextEiPKS3_'], + [['greatest'], 'DECIMAL', ['DECIMAL', '...'], + '_ZN6impala13MathFunctions13LeastGreatestILb0EEEN10impala_udf10DecimalValEPNS2_15FunctionContextEiPKS3_'], + # Decimal Functions # TODO: oracle has decimal support for transcendental functions (e.g. sin()) to very # high precisions. Do we need them? It's unclear if other databases do the same. diff --git a/fe/src/main/java/com/cloudera/impala/analysis/ArithmeticExpr.java b/fe/src/main/java/com/cloudera/impala/analysis/ArithmeticExpr.java index ba332c387..63e29a224 100644 --- a/fe/src/main/java/com/cloudera/impala/analysis/ArithmeticExpr.java +++ b/fe/src/main/java/com/cloudera/impala/analysis/ArithmeticExpr.java @@ -131,12 +131,7 @@ public class ArithmeticExpr extends Expr { @Override protected void toThrift(TExprNode msg) { - if (fn_.getName().equals("_impala_builtins.fmod")) { - // fmod is a math function and not yet implemented as UDF - msg.node_type = TExprNodeType.ARITHMETIC_EXPR; - } else { - msg.node_type = TExprNodeType.FUNCTION_CALL; - } + msg.node_type = TExprNodeType.FUNCTION_CALL; } /** diff --git a/testdata/workloads/functional-query/queries/QueryTest/exprs.test b/testdata/workloads/functional-query/queries/QueryTest/exprs.test index f5779e3f9..4d08b0443 100644 --- a/testdata/workloads/functional-query/queries/QueryTest/exprs.test +++ b/testdata/workloads/functional-query/queries/QueryTest/exprs.test @@ -1691,3 +1691,11 @@ select 1.1 * 1.1 + c3 from functional.decimal_tiny limit 2; ---- TYPES decimal ==== +---- QUERY +# Test weird log values (these are annoying to check in expr-test) +select log(1,2), log(1,1), log(0,2), log(2,0), log(0,0); +---- RESULTS +Infinity,NaN,-0,-Infinity,Nan +---- TYPES +double,double,double,double,double +====