IMPALA-4435: Fix in-predicate-benchmark linking by moving templates In C++ (without export, which was removed in C++11), templates definitions (and not just declarations) must be in headers in order to be implicitly instantiated by callers. in-predicate-benchmark was http://gerrit.cloudera.org:8080/4758; this patch fixes the linker errors that were caused in some build modes by #including only the template declarations.
Change-Id: Ie95ec71242b97f28c68e37d6f44956f2eeff8105 Reviewed-on: http://gerrit.cloudera.org:8080/4966 Reviewed-by: Jim Apple <[email protected]> Tested-by: Internal Jenkins Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/7c001888 Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/7c001888 Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/7c001888 Branch: refs/heads/hadoop-next Commit: 7c0018881b5c111ab175bbbc678bebc902126f5a Parents: 120f34b Author: Jim Apple <[email protected]> Authored: Sat Nov 5 07:08:27 2016 -0700 Committer: Internal Jenkins <[email protected]> Committed: Sun Nov 6 01:51:59 2016 +0000 ---------------------------------------------------------------------- be/src/exprs/in-predicate-ir.cc | 110 -------------------------------- be/src/exprs/in-predicate.h | 117 ++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 113 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/7c001888/be/src/exprs/in-predicate-ir.cc ---------------------------------------------------------------------- diff --git a/be/src/exprs/in-predicate-ir.cc b/be/src/exprs/in-predicate-ir.cc index 51aeec9..998fae0 100644 --- a/be/src/exprs/in-predicate-ir.cc +++ b/be/src/exprs/in-predicate-ir.cc @@ -19,118 +19,12 @@ #include "exprs/in-predicate.h" -#include "exprs/anyval-util.h" -#include "runtime/decimal-value.h" -#include "runtime/string-value.inline.h" - #include "common/names.h" using namespace impala_udf; namespace impala { -// Templated getter functions for extracting 'SetType' values from AnyVals -template<typename T, typename SetType> -SetType GetVal(const FunctionContext::TypeDesc* type, const T& x) { - DCHECK(!x.is_null); - return x.val; -} - -template<> StringValue GetVal(const FunctionContext::TypeDesc* type, const StringVal& x) { - DCHECK(!x.is_null); - return StringValue::FromStringVal(x); -} - -template<> TimestampValue GetVal( - const FunctionContext::TypeDesc* type, const TimestampVal& x) { - return TimestampValue::FromTimestampVal(x); -} - -template<> Decimal16Value GetVal( - const FunctionContext::TypeDesc* type, const DecimalVal& x) { - if (type->precision <= ColumnType::MAX_DECIMAL4_PRECISION) { - return Decimal16Value(x.val4); - } else if (type->precision <= ColumnType::MAX_DECIMAL8_PRECISION) { - return Decimal16Value(x.val8); - } else { - return Decimal16Value(x.val16); - } -} - -template<typename T, typename SetType> -void InPredicate::SetLookupPrepare( - FunctionContext* ctx, FunctionContext::FunctionStateScope scope) { - if (scope != FunctionContext::FRAGMENT_LOCAL) return; - - SetLookupState<SetType>* state = new SetLookupState<SetType>; - state->type = ctx->GetArgType(0); - state->contains_null = false; - for (int i = 1; i < ctx->GetNumArgs(); ++i) { - DCHECK(ctx->IsArgConstant(i)); - T* arg = reinterpret_cast<T*>(ctx->GetConstantArg(i)); - if (arg->is_null) { - state->contains_null = true; - } else { - state->val_set.insert(GetVal<T, SetType>(state->type, *arg)); - } - } - ctx->SetFunctionState(scope, state); -} - -template<typename SetType> -void InPredicate::SetLookupClose( - FunctionContext* ctx, FunctionContext::FunctionStateScope scope) { - if (scope != FunctionContext::FRAGMENT_LOCAL) return; - SetLookupState<SetType>* state = - reinterpret_cast<SetLookupState<SetType>*>(ctx->GetFunctionState(scope)); - delete state; -} - -template<typename T, typename SetType, bool not_in, InPredicate::Strategy strategy> -BooleanVal InPredicate::TemplatedIn( - FunctionContext* ctx, const T& val, int num_args, const T* args) { - if (val.is_null) return BooleanVal::null(); - - BooleanVal found; - if (strategy == SET_LOOKUP) { - SetLookupState<SetType>* state = reinterpret_cast<SetLookupState<SetType>*>( - ctx->GetFunctionState(FunctionContext::FRAGMENT_LOCAL)); - DCHECK(state != NULL); - found = SetLookup(state, val); - } else { - DCHECK_EQ(strategy, ITERATE); - found = Iterate(ctx->GetArgType(0), val, num_args, args); - } - if (found.is_null) return BooleanVal::null(); - return BooleanVal(found.val ^ not_in); -} - -template<typename T, typename SetType> -BooleanVal InPredicate::SetLookup( - SetLookupState<SetType>* state, const T& v) { - DCHECK(state != NULL); - SetType val = GetVal<T, SetType>(state->type, v); - bool found = state->val_set.find(val) != state->val_set.end(); - if (found) return BooleanVal(true); - if (state->contains_null) return BooleanVal::null(); - return BooleanVal(false); -} - -template<typename T> -BooleanVal InPredicate::Iterate( - const FunctionContext::TypeDesc* type, const T& val, int num_args, const T* args) { - bool found_null = false; - for (int i = 0; i < num_args; ++i) { - if (args[i].is_null) { - found_null = true; - } else if (AnyValUtil::Equals(*type, val, args[i])) { - return BooleanVal(true); - } - } - if (found_null) return BooleanVal::null(); - return BooleanVal(false); -} - #define IN_FUNCTIONS(AnyValType, SetType, type_name) \ BooleanVal InPredicate::InSetLookup( \ FunctionContext* context, const AnyValType& val, int num_args, \ @@ -181,8 +75,4 @@ IN_FUNCTIONS(StringVal, StringValue, string) IN_FUNCTIONS(TimestampVal, TimestampValue, timestamp) IN_FUNCTIONS(DecimalVal, Decimal16Value, decimal) -// Needed for in-predicate-benchmark to build -template BooleanVal InPredicate::Iterate<IntVal>( - const FunctionContext::TypeDesc*, const IntVal&, int, const IntVal*); - } http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/7c001888/be/src/exprs/in-predicate.h ---------------------------------------------------------------------- diff --git a/be/src/exprs/in-predicate.h b/be/src/exprs/in-predicate.h index d01d844..fd53a42 100644 --- a/be/src/exprs/in-predicate.h +++ b/be/src/exprs/in-predicate.h @@ -21,6 +21,9 @@ #include <string> #include "exprs/predicate.h" +#include "exprs/anyval-util.h" +#include "runtime/decimal-value.h" +#include "runtime/string-value.inline.h" #include "udf/udf.h" namespace impala { @@ -293,7 +296,7 @@ class InPredicate : public Predicate { /// functions. template<typename T, typename SetType, bool not_in, Strategy strategy> static inline impala_udf::BooleanVal TemplatedIn( - impala_udf::FunctionContext* context, const T& val, int num_args, const T* args); + impala_udf::FunctionContext* ctx, const T& val, int num_args, const T* args); /// Initializes an SetLookupState in ctx. template<typename T, typename SetType> @@ -308,12 +311,120 @@ class InPredicate : public Predicate { template<typename T, typename SetType> static BooleanVal SetLookup(SetLookupState<SetType>* state, const T& v); - /// Iterates through each vararg looking for val. 'type' is the type of 'val' and 'args'. - template<typename T> + /// Iterates through each vararg looking for val. 'type' is the type of 'val' and + /// 'args'. + template <typename T> static BooleanVal Iterate( const FunctionContext::TypeDesc* type, const T& val, int num_args, const T* args); + + // Templated getter functions for extracting 'SetType' values from AnyVals + template <typename T, typename SetType> + static inline SetType GetVal(const FunctionContext::TypeDesc* type, const T& x); }; +template <typename T, typename SetType, bool not_in, InPredicate::Strategy strategy> +inline impala_udf::BooleanVal InPredicate::TemplatedIn( + impala_udf::FunctionContext* ctx, const T& val, int num_args, const T* args) { + if (val.is_null) return BooleanVal::null(); + + BooleanVal found; + if (strategy == SET_LOOKUP) { + SetLookupState<SetType>* state = reinterpret_cast<SetLookupState<SetType>*>( + ctx->GetFunctionState(FunctionContext::FRAGMENT_LOCAL)); + DCHECK(state != NULL); + found = SetLookup(state, val); + } else { + DCHECK_EQ(strategy, ITERATE); + found = Iterate(ctx->GetArgType(0), val, num_args, args); + } + if (found.is_null) return BooleanVal::null(); + return BooleanVal(found.val ^ not_in); +} + +template <typename T, typename SetType> +void InPredicate::SetLookupPrepare( + FunctionContext* ctx, FunctionContext::FunctionStateScope scope) { + if (scope != FunctionContext::FRAGMENT_LOCAL) return; + + SetLookupState<SetType>* state = new SetLookupState<SetType>; + state->type = ctx->GetArgType(0); + state->contains_null = false; + for (int i = 1; i < ctx->GetNumArgs(); ++i) { + DCHECK(ctx->IsArgConstant(i)); + T* arg = reinterpret_cast<T*>(ctx->GetConstantArg(i)); + if (arg->is_null) { + state->contains_null = true; + } else { + state->val_set.insert(GetVal<T, SetType>(state->type, *arg)); + } + } + ctx->SetFunctionState(scope, state); +} + +template <typename SetType> +void InPredicate::SetLookupClose( + FunctionContext* ctx, FunctionContext::FunctionStateScope scope) { + if (scope != FunctionContext::FRAGMENT_LOCAL) return; + SetLookupState<SetType>* state = + reinterpret_cast<SetLookupState<SetType>*>(ctx->GetFunctionState(scope)); + delete state; +} + +template <typename T, typename SetType> +BooleanVal InPredicate::SetLookup(SetLookupState<SetType>* state, const T& v) { + DCHECK(state != NULL); + SetType val = GetVal<T, SetType>(state->type, v); + bool found = state->val_set.find(val) != state->val_set.end(); + if (found) return BooleanVal(true); + if (state->contains_null) return BooleanVal::null(); + return BooleanVal(false); +} + +template <typename T> +BooleanVal InPredicate::Iterate( + const FunctionContext::TypeDesc* type, const T& val, int num_args, const T* args) { + bool found_null = false; + for (int i = 0; i < num_args; ++i) { + if (args[i].is_null) { + found_null = true; + } else if (AnyValUtil::Equals(*type, val, args[i])) { + return BooleanVal(true); + } + } + if (found_null) return BooleanVal::null(); + return BooleanVal(false); +} + +template <typename T, typename SetType> +inline SetType InPredicate::GetVal(const FunctionContext::TypeDesc* type, const T& x) { + DCHECK(!x.is_null); + return x.val; +} + +template <> +inline StringValue InPredicate::GetVal( + const FunctionContext::TypeDesc* type, const StringVal& x) { + DCHECK(!x.is_null); + return StringValue::FromStringVal(x); +} + +template <> +inline TimestampValue InPredicate::GetVal( + const FunctionContext::TypeDesc* type, const TimestampVal& x) { + return TimestampValue::FromTimestampVal(x); +} + +template <> +inline Decimal16Value InPredicate::GetVal( + const FunctionContext::TypeDesc* type, const DecimalVal& x) { + if (type->precision <= ColumnType::MAX_DECIMAL4_PRECISION) { + return Decimal16Value(x.val4); + } else if (type->precision <= ColumnType::MAX_DECIMAL8_PRECISION) { + return Decimal16Value(x.val8); + } else { + return Decimal16Value(x.val16); + } +} } #endif
