Skip to content

Commit

Permalink
added castvarchar(numeric_types) functions
Browse files Browse the repository at this point in the history
  • Loading branch information
projjal committed Oct 9, 2020
1 parent f0f7593 commit 5c202e5
Show file tree
Hide file tree
Showing 7 changed files with 412 additions and 0 deletions.
1 change: 1 addition & 0 deletions cpp/src/gandiva/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ add_gandiva_test(internals-test
like_holder_test.cc
decimal_type_util_test.cc
random_generator_holder_test.cc
gdv_function_stubs_test.cc
EXTRA_DEPENDENCIES
LLVM::LLVM_INTERFACE
EXTRA_INCLUDES
Expand Down
17 changes: 17 additions & 0 deletions cpp/src/gandiva/function_registry_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.

#include "gandiva/function_registry_string.h"

#include "gandiva/function_registry_common.h"

namespace gandiva {
Expand Down Expand Up @@ -76,6 +77,22 @@ std::vector<NativeFunction> GetStringFunctionRegistry() {
kResultNullIfNull, "castVARCHAR_utf8_int64",
NativeFunction::kNeedsContext),

NativeFunction("castVARCHAR", {}, DataTypeVector{int32(), int64()}, utf8(),
kResultNullIfNull, "gdv_fn_castVARCHAR_int32_int64",
NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),

NativeFunction("castVARCHAR", {}, DataTypeVector{int64(), int64()}, utf8(),
kResultNullIfNull, "gdv_fn_castVARCHAR_int64_int64",
NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),

NativeFunction("castVARCHAR", {}, DataTypeVector{float32(), int64()}, utf8(),
kResultNullIfNull, "gdv_fn_castVARCHAR_float32_int64",
NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),

NativeFunction("castVARCHAR", {}, DataTypeVector{float64(), int64()}, utf8(),
kResultNullIfNull, "gdv_fn_castVARCHAR_float64_int64",
NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),

NativeFunction("castVARCHAR", {}, DataTypeVector{decimal128(), int64()}, utf8(),
kResultNullIfNull, "castVARCHAR_decimal128_int64",
NativeFunction::kNeedsContext),
Expand Down
81 changes: 81 additions & 0 deletions cpp/src/gandiva/gdv_function_stubs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@

#include "gandiva/gdv_function_stubs.h"

#include <cstdlib>
#include <string>
#include <vector>

#include "arrow/util/formatting.h"
#include "gandiva/engine.h"
#include "gandiva/exported_funcs.h"
#include "gandiva/in_holder.h"
#include "gandiva/like_holder.h"
#include "gandiva/precompiled/types.h"
#include "gandiva/random_generator_holder.h"
#include "gandiva/to_date_holder.h"

Expand Down Expand Up @@ -150,6 +153,48 @@ char* gdv_fn_dec_to_string(int64_t context, int64_t x_high, uint64_t x_low,
memcpy(ret, dec_str.data(), *dec_str_len);
return ret;
}

#define GDV_FN_CAST_VARCHAR(IN_TYPE, ARROW_TYPE) \
GANDIVA_EXPORT \
const char* gdv_fn_castVARCHAR_##IN_TYPE##_int64(int64_t context, gdv_##IN_TYPE value, \
int64_t len, int32_t * out_len) { \
if (len < 0) { \
gdv_fn_context_set_error_msg(context, "Buffer length can not be negative"); \
*out_len = 0; \
return ""; \
} \
if (len == 0) { \
*out_len = 0; \
return ""; \
} \
arrow::internal::StringFormatter<arrow::ARROW_TYPE> formatter; \
char* ret = reinterpret_cast<char*>( \
gdv_fn_context_arena_malloc(context, static_cast<int32_t>(len))); \
if (ret == nullptr) { \
gdv_fn_context_set_error_msg(context, "Could not allocate memory"); \
*out_len = 0; \
return ""; \
} \
arrow::Status status = formatter(value, [&](arrow::util::string_view v) { \
int64_t size = static_cast<int64_t>(v.size()); \
*out_len = static_cast<int32_t>(len < size ? len : size); \
memcpy(ret, v.data(), *out_len); \
return arrow::Status::OK(); \
}); \
if (!status.ok()) { \
gdv_fn_context_set_error_msg(context, "Could not cast to string"); \
*out_len = 0; \
return ""; \
} \
return ret; \
}

GDV_FN_CAST_VARCHAR(int32, Int32Type)
GDV_FN_CAST_VARCHAR(int64, Int64Type)
GDV_FN_CAST_VARCHAR(float32, FloatType)
GDV_FN_CAST_VARCHAR(float64, DoubleType)

#undef GDV_FN_CAST_VARCHAR
}

namespace gandiva {
Expand Down Expand Up @@ -277,6 +322,42 @@ void ExportedStubFunctions::AddMappings(Engine* engine) const {
args = {types->i64_type(), types->i32_type(), types->i1_type()};
engine->AddGlobalMappingForFunc("gdv_fn_random_with_seed", types->double_type(), args,
reinterpret_cast<void*>(gdv_fn_random_with_seed));

// gdv_fn_castVARCHAR_int32_int64
args = {types->i64_type(), // int64_t execution_context
types->i32_type(), // int32_t value
types->i64_type(), // int64_t len
types->i32_ptr_type()}; // int32_t* out_len
engine->AddGlobalMappingForFunc(
"gdv_fn_castVARCHAR_int32_int64", types->i8_ptr_type() /*return_type*/, args,
reinterpret_cast<void*>(gdv_fn_castVARCHAR_int32_int64));

// gdv_fn_castVARCHAR_int64_int64
args = {types->i64_type(), // int64_t execution_context
types->i64_type(), // int64_t value
types->i64_type(), // int64_t len
types->i32_ptr_type()}; // int32_t* out_len
engine->AddGlobalMappingForFunc(
"gdv_fn_castVARCHAR_int64_int64", types->i8_ptr_type() /*return_type*/, args,
reinterpret_cast<void*>(gdv_fn_castVARCHAR_int64_int64));

// gdv_fn_castVARCHAR_float32_int64
args = {types->i64_type(), // int64_t execution_context
types->float_type(), // float value
types->i64_type(), // int64_t len
types->i32_ptr_type()}; // int32_t* out_len
engine->AddGlobalMappingForFunc(
"gdv_fn_castVARCHAR_float32_int64", types->i8_ptr_type() /*return_type*/, args,
reinterpret_cast<void*>(gdv_fn_castVARCHAR_float32_int64));

// gdv_fn_castVARCHAR_float64_int64
args = {types->i64_type(), // int64_t execution_context
types->double_type(), // double value
types->i64_type(), // int64_t len
types->i32_ptr_type()}; // int32_t* out_len
engine->AddGlobalMappingForFunc(
"gdv_fn_castVARCHAR_float64_int64", types->i8_ptr_type() /*return_type*/, args,
reinterpret_cast<void*>(gdv_fn_castVARCHAR_float64_int64));
}

} // namespace gandiva
15 changes: 15 additions & 0 deletions cpp/src/gandiva/gdv_function_stubs.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include <cstdint>

#include "gandiva/visibility.h"

/// Stub functions that can be accessed from LLVM.
extern "C" {

Expand Down Expand Up @@ -52,4 +54,17 @@ int32_t gdv_fn_dec_from_string(int64_t context, const char* in, int32_t in_lengt

char* gdv_fn_dec_to_string(int64_t context, int64_t x_high, uint64_t x_low,
int32_t x_scale, int32_t* dec_str_len);

GANDIVA_EXPORT
const char* gdv_fn_castVARCHAR_int32_int64(int64_t context, int32_t value, int64_t len,
int32_t* out_len);
GANDIVA_EXPORT
const char* gdv_fn_castVARCHAR_int64_int64(int64_t context, int64_t value, int64_t len,
int32_t* out_len);
GANDIVA_EXPORT
const char* gdv_fn_castVARCHAR_float32_int64(int64_t context, float value, int64_t len,
int32_t* out_len);
GANDIVA_EXPORT
const char* gdv_fn_castVARCHAR_float64_int64(int64_t context, double value, int64_t len,
int32_t* out_len);
}
141 changes: 141 additions & 0 deletions cpp/src/gandiva/gdv_function_stubs_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// 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/gdv_function_stubs.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "gandiva/execution_context.h"

namespace gandiva {

TEST(TestGdvFnStubs, TestCastVARCHARFromInt32) {
gandiva::ExecutionContext ctx;
uint64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
int32_t out_len = 0;

const char* out_str = gdv_fn_castVARCHAR_int32_int64(ctx_ptr, -46, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "-46");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_int32_int64(ctx_ptr, 2147483647, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "2147483647");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_int32_int64(ctx_ptr, -2147483647 - 1, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "-2147483648");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_int32_int64(ctx_ptr, 0, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "0");
EXPECT_FALSE(ctx.has_error());

// test with required length less than actual buffer length
out_str = gdv_fn_castVARCHAR_int32_int64(ctx_ptr, 34567, 3, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "345");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_int32_int64(ctx_ptr, 347, 0, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_int32_int64(ctx_ptr, 347, -1, &out_len);
EXPECT_THAT(ctx.get_error(), ::testing::HasSubstr("Buffer length can not be negative"));
ctx.Reset();
}

TEST(TestGdvFnStubs, TestCastVARCHARFromInt64) {
gandiva::ExecutionContext ctx;
uint64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
int32_t out_len = 0;

const char* out_str =
gdv_fn_castVARCHAR_int64_int64(ctx_ptr, 9223372036854775807LL, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "9223372036854775807");
EXPECT_FALSE(ctx.has_error());

out_str =
gdv_fn_castVARCHAR_int64_int64(ctx_ptr, -9223372036854775807LL - 1, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "-9223372036854775808");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_int64_int64(ctx_ptr, 0, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "0");
EXPECT_FALSE(ctx.has_error());

// test with required length less than actual buffer length
out_str = gdv_fn_castVARCHAR_int64_int64(ctx_ptr, 12345, 3, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "123");
EXPECT_FALSE(ctx.has_error());
}

TEST(TestGdvFnStubs, TestCastVARCHARFromFloat) {
gandiva::ExecutionContext ctx;
uint64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
int32_t out_len = 0;

const char* out_str = gdv_fn_castVARCHAR_float32_int64(ctx_ptr, 4.567f, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "4.567");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_float32_int64(ctx_ptr, -3.4567f, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "-3.4567");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_float32_int64(ctx_ptr, 0.00001f, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "0.00001");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_float32_int64(ctx_ptr, 0.0f, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "0");
EXPECT_FALSE(ctx.has_error());

// test with required length less than actual buffer length
out_str = gdv_fn_castVARCHAR_float32_int64(ctx_ptr, 1.2345f, 3, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "1.2");
EXPECT_FALSE(ctx.has_error());
}

TEST(TestGdvFnStubs, TestCastVARCHARFromDouble) {
gandiva::ExecutionContext ctx;
uint64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
int32_t out_len = 0;

const char* out_str = gdv_fn_castVARCHAR_float64_int64(ctx_ptr, 4.567, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "4.567");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_float64_int64(ctx_ptr, -3.4567, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "-3.4567");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_float64_int64(ctx_ptr, 0.00001, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "0.00001");
EXPECT_FALSE(ctx.has_error());

out_str = gdv_fn_castVARCHAR_float64_int64(ctx_ptr, 0.0, 100, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "0");
EXPECT_FALSE(ctx.has_error());

// test with required length less than actual buffer length
out_str = gdv_fn_castVARCHAR_float64_int64(ctx_ptr, 1.2345, 3, &out_len);
EXPECT_EQ(std::string(out_str, out_len), "1.2");
EXPECT_FALSE(ctx.has_error());
}

} // namespace gandiva
1 change: 1 addition & 0 deletions cpp/src/gandiva/precompiled/string_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "./types.h"

FORCE_INLINE
Expand Down
Loading

0 comments on commit 5c202e5

Please sign in to comment.