Skip to content

Commit

Permalink
IMPALA-1477: implement UUID function
Browse files Browse the repository at this point in the history
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
  • Loading branch information
usernameafer authored and Internal Jenkins committed Feb 3, 2016
1 parent 8721511 commit 12d605d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
22 changes: 22 additions & 0 deletions be/src/exprs/expr-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions be/src/exprs/utility-functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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));
Expand Down
7 changes: 7 additions & 0 deletions be/src/exprs/utility-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions common/function-registry/impala_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,10 @@ def symbol(class_name, fn_name, templated_type = None):
[['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'],
Expand Down

0 comments on commit 12d605d

Please sign in to comment.