mirror of
https://github.com/apache/impala.git
synced 2025-12-25 02:03:09 -05:00
IMPALA-1477: implement UUID function
Utilize Boost UUID libraries to generate UUID values. Usage: select uuid(); Change-Id: I932f78952d65f4073d8177c6e80693586e6285cb Reviewed-on: http://gerrit.cloudera.org:8080/647 Reviewed-by: Alex Behm <alex.behm@cloudera.com> Tested-by: Internal Jenkins
This commit is contained in:
committed by
Internal Jenkins
parent
5d2bc776cd
commit
df599b79d9
@@ -22,6 +22,7 @@
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -305,6 +306,16 @@ class ExprTest : public testing::Test {
|
||||
EXPECT_EQ(expected_result, tmp) << expr;
|
||||
}
|
||||
|
||||
string TestStringValueRegex(const string& expr, const string& regex) {
|
||||
StringValue* result;
|
||||
GetValue(expr, TYPE_STRING, reinterpret_cast<void **>(&result));
|
||||
static const boost::regex e(regex);
|
||||
string result_cxxstr(result->ptr, result->len);
|
||||
const bool is_regex_match = regex_match(result_cxxstr, e);
|
||||
EXPECT_TRUE(is_regex_match);
|
||||
return result_cxxstr;
|
||||
}
|
||||
|
||||
// We can't put this into TestValue() because GTest can't resolve
|
||||
// the ambiguity in TimestampValue::operator==, even with the appropriate casts.
|
||||
void TestTimestampValue(const string& expr, const TimestampValue& expected_result) {
|
||||
@@ -5718,7 +5729,18 @@ TEST_F(ExprTest, BitByteBuiltins) {
|
||||
TestValue("shiftright(cast(1 as BIGINT), -2)", TYPE_BIGINT, 4);
|
||||
TestValue("rotateleft(4, -3)", TYPE_TINYINT, -128);
|
||||
TestValue("rotateright(256, -2)", TYPE_SMALLINT, 1024);
|
||||
}
|
||||
|
||||
TEST_F(ExprTest, UuidTest) {
|
||||
boost::unordered_set<string> string_set;
|
||||
const unsigned int NUM_UUIDS = 10;
|
||||
const string regex(
|
||||
"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
|
||||
for (int i = 0; i < NUM_UUIDS; ++i) {
|
||||
const string uuid_str = TestStringValueRegex("uuid()", regex);
|
||||
string_set.insert(uuid_str);
|
||||
}
|
||||
EXPECT_TRUE(string_set.size() == NUM_UUIDS);
|
||||
}
|
||||
|
||||
} // namespace impala
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include "exprs/utility-functions.h"
|
||||
|
||||
#include <gutil/strings/substitute.h>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
||||
#include "exprs/anyval-util.h"
|
||||
#include "runtime/runtime-state.h"
|
||||
@@ -111,6 +114,37 @@ StringVal UtilityFunctions::CurrentDatabase(FunctionContext* ctx) {
|
||||
return (database.len > 0) ? database : StringVal::null();
|
||||
}
|
||||
|
||||
void UtilityFunctions::UuidPrepare(FunctionContext* ctx,
|
||||
FunctionContext::FunctionStateScope scope) {
|
||||
if (scope == FunctionContext::THREAD_LOCAL) {
|
||||
if (ctx->GetFunctionState(FunctionContext::THREAD_LOCAL) == NULL) {
|
||||
boost::uuids::random_generator* uuid_gen =
|
||||
new boost::uuids::random_generator;
|
||||
ctx->SetFunctionState(scope, uuid_gen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringVal UtilityFunctions::Uuid(FunctionContext* ctx) {
|
||||
void* uuid_gen = ctx->GetFunctionState(FunctionContext::THREAD_LOCAL);
|
||||
DCHECK(uuid_gen != NULL);
|
||||
boost::uuids::uuid uuid_value =
|
||||
(*reinterpret_cast<boost::uuids::random_generator*>(uuid_gen))();
|
||||
const std::string cxx_string = boost::uuids::to_string(uuid_value);
|
||||
return StringVal::CopyFrom(ctx,
|
||||
reinterpret_cast<const uint8_t*>(cxx_string.c_str()),
|
||||
cxx_string.length());
|
||||
}
|
||||
|
||||
void UtilityFunctions::UuidClose(FunctionContext* ctx,
|
||||
FunctionContext::FunctionStateScope scope){
|
||||
if (scope == FunctionContext::THREAD_LOCAL) {
|
||||
void* uuid_gen = ctx->GetFunctionState(FunctionContext::THREAD_LOCAL);
|
||||
DCHECK(uuid_gen != NULL);
|
||||
delete uuid_gen;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StringVal UtilityFunctions::TypeOf(FunctionContext* ctx, const T& /*input_val*/) {
|
||||
FunctionContext::TypeDesc type_desc = *(ctx->GetArgType(0));
|
||||
|
||||
@@ -58,6 +58,13 @@ class UtilityFunctions {
|
||||
/// database from the parent session of this query.
|
||||
static StringVal CurrentDatabase(FunctionContext* ctx);
|
||||
|
||||
/// Implementation of the Uuid() function.
|
||||
static StringVal Uuid(FunctionContext* ctx);
|
||||
static void UuidPrepare(FunctionContext* ctx,
|
||||
FunctionContext::FunctionStateScope scope);
|
||||
static void UuidClose(FunctionContext* ctx,
|
||||
FunctionContext::FunctionStateScope scope);
|
||||
|
||||
/// Implementation of the typeOf() function. Returns the type of the input
|
||||
/// expression. input_val is not used and it is kept here in order to let
|
||||
/// the compiler generate the corresponding fully-qualified function name.
|
||||
|
||||
@@ -535,6 +535,10 @@ visible_functions = [
|
||||
[['isnotfalse'], 'BOOLEAN', ['BOOLEAN'], 'impala::ConditionalFunctions::IsNotFalse'],
|
||||
|
||||
# Utility functions
|
||||
[['uuid'], 'STRING', [],
|
||||
'_ZN6impala16UtilityFunctions4UuidEPN10impala_udf15FunctionContextE',
|
||||
'_ZN6impala16UtilityFunctions11UuidPrepareEPN10impala_udf15FunctionContextENS2_18FunctionStateScopeE',
|
||||
'_ZN6impala16UtilityFunctions9UuidCloseEPN10impala_udf15FunctionContextENS2_18FunctionStateScopeE'],
|
||||
[['current_database'], 'STRING', [], 'impala::UtilityFunctions::CurrentDatabase'],
|
||||
[['user'], 'STRING', [], 'impala::UtilityFunctions::User'],
|
||||
[['effective_user'], 'STRING', [], 'impala::UtilityFunctions::EffectiveUser'],
|
||||
|
||||
Reference in New Issue
Block a user