This is an automated email from the ASF dual-hosted git repository. yangzhg pushed a commit to branch revert-8263-remove_code in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
commit 4ce2b4a1f75f7aee14a03f691cf1ddf103f211ba Author: Zhengguo Yang <780531...@qq.com> AuthorDate: Mon Mar 7 15:44:25 2022 +0800 Revert "[refactor] remove unused new_in_predicate code (#8263)" This reverts commit 757e35744d4f6319e936fca84b4be13cf043a578. --- be/src/common/daemon.cpp | 2 + be/src/exprs/CMakeLists.txt | 1 + be/src/exprs/new_in_predicate.cpp | 185 ++++++++++++++++++++ be/src/exprs/new_in_predicate.h | 348 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 536 insertions(+) diff --git a/be/src/common/daemon.cpp b/be/src/common/daemon.cpp index 04625e3..044feda 100644 --- a/be/src/common/daemon.cpp +++ b/be/src/common/daemon.cpp @@ -37,6 +37,7 @@ #include "exprs/json_functions.h" #include "exprs/like_predicate.h" #include "exprs/math_functions.h" +#include "exprs/new_in_predicate.h" #include "exprs/operators.h" #include "exprs/string_functions.h" #include "exprs/table_function/dummy_table_functions.h" @@ -249,6 +250,7 @@ void Daemon::init(int argc, char** argv, const std::vector<StorePath>& paths) { StringFunctions::init(); ArrayFunctions::init(); CastFunctions::init(); + InPredicate::init(); MathFunctions::init(); EncryptionFunctions::init(); TimestampFunctions::init(); diff --git a/be/src/exprs/CMakeLists.txt b/be/src/exprs/CMakeLists.txt index f266fd9..c71f23e 100644 --- a/be/src/exprs/CMakeLists.txt +++ b/be/src/exprs/CMakeLists.txt @@ -41,6 +41,7 @@ add_library(Exprs expr.cpp expr_context.cpp in_predicate.cpp + new_in_predicate.cpp bloomfilter_predicate.cpp block_bloom_filter_avx_impl.cc block_bloom_filter_impl.cc diff --git a/be/src/exprs/new_in_predicate.cpp b/be/src/exprs/new_in_predicate.cpp new file mode 100644 index 0000000..b0a6390 --- /dev/null +++ b/be/src/exprs/new_in_predicate.cpp @@ -0,0 +1,185 @@ +// 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 "exprs/new_in_predicate.h" + +#include <sstream> + +#include "exprs/anyval_util.h" +#include "runtime/string_value.hpp" + +namespace doris { + +void InPredicate::init() {} + +// Templated getter functions for extracting 'SetType' values from AnyVals +template <typename T, typename SetType> +SetType get_val(const FunctionContext::TypeDesc* type, const T& x) { + DCHECK(!x.is_null); + return x.val; +} + +template <> +StringValue get_val(const FunctionContext::TypeDesc* type, const StringVal& x) { + DCHECK(!x.is_null); + return StringValue::from_string_val(x); +} + +template <> +DateTimeValue get_val(const FunctionContext::TypeDesc* type, const DateTimeVal& x) { + return DateTimeValue::from_datetime_val(x); +} + +template <> +DecimalV2Value get_val(const FunctionContext::TypeDesc* type, const DecimalV2Val& x) { + return DecimalV2Value::from_decimal_val(x); +} + +template <typename T, typename SetType> +void InPredicate::set_lookup_prepare(FunctionContext* ctx, + FunctionContext::FunctionStateScope scope) { + if (scope != FunctionContext::FRAGMENT_LOCAL) { + return; + } + + SetLookupState<SetType>* state = new SetLookupState<SetType>; + state->type = ctx->get_arg_type(0); + state->contains_null = false; + for (int i = 1; i < ctx->get_num_args(); ++i) { + DCHECK(ctx->is_arg_constant(i)); + T* arg = reinterpret_cast<T*>(ctx->get_constant_arg(i)); + if (arg->is_null) { + state->contains_null = true; + } else { + state->val_set.insert(get_val<T, SetType>(state->type, *arg)); + } + } + ctx->set_function_state(scope, state); +} + +template <typename SetType> +void InPredicate::set_lookup_close(FunctionContext* ctx, + FunctionContext::FunctionStateScope scope) { + if (scope != FunctionContext::FRAGMENT_LOCAL) { + return; + } + SetLookupState<SetType>* state = + reinterpret_cast<SetLookupState<SetType>*>(ctx->get_function_state(scope)); + delete state; +} + +template <typename T, typename SetType, bool not_in, InPredicate::Strategy strategy> +BooleanVal InPredicate::templated_in(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->get_function_state(FunctionContext::FRAGMENT_LOCAL)); + DCHECK(state != nullptr); + found = set_lookup(state, val); + } else { + DCHECK_EQ(strategy, ITERATE); + found = iterate(ctx->get_arg_type(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::set_lookup(SetLookupState<SetType>* state, const T& v) { + DCHECK(state != nullptr); + SetType val = get_val<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::in_set_lookup(FunctionContext* context, const AnyValType& val, \ + int num_args, const AnyValType* args) { \ + return templated_in<AnyValType, SetType, false, SET_LOOKUP>(context, val, num_args, args); \ + } \ + \ + BooleanVal InPredicate::not_in_set_lookup(FunctionContext* context, const AnyValType& val, \ + int num_args, const AnyValType* args) { \ + return templated_in<AnyValType, SetType, true, SET_LOOKUP>(context, val, num_args, args); \ + } \ + \ + BooleanVal InPredicate::in_iterate(FunctionContext* context, const AnyValType& val, \ + int num_args, const AnyValType* args) { \ + return templated_in<AnyValType, SetType, false, ITERATE>(context, val, num_args, args); \ + } \ + \ + BooleanVal InPredicate::not_in_iterate(FunctionContext* context, const AnyValType& val, \ + int num_args, const AnyValType* args) { \ + return templated_in<AnyValType, SetType, true, ITERATE>(context, val, num_args, args); \ + } \ + \ + void InPredicate::set_lookup_prepare_##type_name(FunctionContext* ctx, \ + FunctionContext::FunctionStateScope scope) { \ + set_lookup_prepare<AnyValType, SetType>(ctx, scope); \ + } \ + \ + void InPredicate::set_lookup_close_##type_name(FunctionContext* ctx, \ + FunctionContext::FunctionStateScope scope) { \ + set_lookup_close<SetType>(ctx, scope); \ + } + +IN_FUNCTIONS(BooleanVal, bool, boolean_val) +IN_FUNCTIONS(TinyIntVal, int8_t, tiny_int_val) +IN_FUNCTIONS(SmallIntVal, int16_t, small_int_val) +IN_FUNCTIONS(IntVal, int32_t, int_val) +IN_FUNCTIONS(BigIntVal, int64_t, big_int_val) +IN_FUNCTIONS(FloatVal, float, float_val) +IN_FUNCTIONS(DoubleVal, double, double_val) +IN_FUNCTIONS(StringVal, StringValue, string_val) +IN_FUNCTIONS(DateTimeVal, DateTimeValue, datetime_val) +IN_FUNCTIONS(DecimalV2Val, DecimalV2Value, decimalv2_val) +IN_FUNCTIONS(LargeIntVal, __int128, large_int_val) + +// Needed for in-predicate-benchmark to build +template BooleanVal InPredicate::iterate<IntVal>(const FunctionContext::TypeDesc*, const IntVal&, + int, const IntVal*); +} // namespace doris diff --git a/be/src/exprs/new_in_predicate.h b/be/src/exprs/new_in_predicate.h new file mode 100644 index 0000000..6238894 --- /dev/null +++ b/be/src/exprs/new_in_predicate.h @@ -0,0 +1,348 @@ +// 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. + +#ifndef DORIS_BE_SRC_QUERY_EXPRS_NEW_IN_PREDICATE_H +#define DORIS_BE_SRC_QUERY_EXPRS_NEW_IN_PREDICATE_H + +#include <string> + +#include "exprs/predicate.h" +#include "udf/udf.h" + +/* added by lide */ +#define IN_FUNCTIONS_STMT(AnyValType, SetType, type_name) \ + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, \ + const doris_udf::AnyValType& val, int num_args, \ + const doris_udf::AnyValType* args); \ + \ + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, \ + const doris_udf::AnyValType& val, int num_args, \ + const doris_udf::AnyValType* args); \ + \ + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, \ + const doris_udf::AnyValType& val, int num_args, \ + const doris_udf::AnyValType* args); \ + \ + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, \ + const doris_udf::AnyValType& val, int num_args, \ + const doris_udf::AnyValType* args); \ + \ + static void set_lookup_prepare_##type_name( \ + doris_udf::FunctionContext* ctx, \ + doris_udf::FunctionContext::FunctionStateScope scope); \ + \ + static void set_lookup_close_##type_name( \ + doris_udf::FunctionContext* ctx, \ + doris_udf::FunctionContext::FunctionStateScope scope); + +namespace doris { + +/// Predicate for evaluating expressions of the form "val [NOT] IN (x1, x2, x3...)". +// +/// There are two strategies for evaluating the IN predicate: +// +/// 1) SET_LOOKUP: This strategy is for when all the values in the IN list are constant. In +/// the prepare function, we create a set of the constant values from the IN list, and +/// use this set to lookup a given 'val'. +// +/// 2) ITERATE: This is the fallback strategy for when their are non-constant IN list +/// values, or very few values in the IN list. We simply iterate through every +/// expression and compare it to val. This strategy has no prepare function. +// +/// The FE chooses which strategy we should use by choosing the appropriate function (e.g., +/// in_iterate() or in_set_lookup()). If it chooses SET_LOOKUP, it also sets the appropriate +/// set_lookup_prepare and set_lookup_close functions. +// +/// TODO: the set lookup logic is not yet implemented for DateTimeVals or DecimalVals +class InPredicate { +public: + static void init(); + + /// Functions for every type + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::BooleanVal& val, int num_args, + const doris_udf::BooleanVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::BooleanVal& val, int num_args, + const doris_udf::BooleanVal* args); + + static void set_lookup_prepare_boolean_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_boolean_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::BooleanVal& val, int num_args, + const doris_udf::BooleanVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::BooleanVal& val, int num_args, + const doris_udf::BooleanVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::TinyIntVal& val, int num_args, + const doris_udf::TinyIntVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::TinyIntVal& val, int num_args, + const doris_udf::TinyIntVal* args); + + static void set_lookup_prepare_tiny_int_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_tiny_int_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::TinyIntVal& val, int num_args, + const doris_udf::TinyIntVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::TinyIntVal& val, int num_args, + const doris_udf::TinyIntVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::SmallIntVal& val, int num_args, + const doris_udf::SmallIntVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::SmallIntVal& val, int num_args, + const doris_udf::SmallIntVal* args); + + static void set_lookup_prepare_small_int_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_small_int_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::SmallIntVal& val, int num_args, + const doris_udf::SmallIntVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::SmallIntVal& val, int num_args, + const doris_udf::SmallIntVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::IntVal& val, int num_args, + const doris_udf::IntVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::IntVal& val, int num_args, + const doris_udf::IntVal* args); + + static void set_lookup_prepare_int_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_int_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::IntVal& val, int num_args, + const doris_udf::IntVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::IntVal& val, int num_args, + const doris_udf::IntVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::BigIntVal& val, int num_args, + const doris_udf::BigIntVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::BigIntVal& val, int num_args, + const doris_udf::BigIntVal* args); + + static void set_lookup_prepare_big_int_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_big_int_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::BigIntVal& val, int num_args, + const doris_udf::BigIntVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::BigIntVal& val, int num_args, + const doris_udf::BigIntVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::FloatVal& val, int num_args, + const doris_udf::FloatVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::FloatVal& val, int num_args, + const doris_udf::FloatVal* args); + + static void set_lookup_prepare_float_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_float_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::FloatVal& val, int num_args, + const doris_udf::FloatVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::FloatVal& val, int num_args, + const doris_udf::FloatVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::DoubleVal& val, int num_args, + const doris_udf::DoubleVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::DoubleVal& val, int num_args, + const doris_udf::DoubleVal* args); + + static void set_lookup_prepare_double_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_double_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::DoubleVal& val, int num_args, + const doris_udf::DoubleVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::DoubleVal& val, int num_args, + const doris_udf::DoubleVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::StringVal& val, int num_args, + const doris_udf::StringVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::StringVal& val, int num_args, + const doris_udf::StringVal* args); + + static void set_lookup_prepare_string_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_string_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::StringVal& val, int num_args, + const doris_udf::StringVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::StringVal& val, int num_args, + const doris_udf::StringVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::DateTimeVal& val, int num_args, + const doris_udf::DateTimeVal* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::DateTimeVal& val, int num_args, + const doris_udf::DateTimeVal* args); + + static void set_lookup_prepare_datetime_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_datetime_val(doris_udf::FunctionContext* ctx, + doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::DateTimeVal& val, int num_args, + const doris_udf::DateTimeVal* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::DateTimeVal& val, int num_args, + const doris_udf::DateTimeVal* args); + + static doris_udf::BooleanVal in_iterate(doris_udf::FunctionContext* context, + const doris_udf::DecimalV2Val& val, int num_args, + const doris_udf::DecimalV2Val* args); + + static doris_udf::BooleanVal not_in_iterate(doris_udf::FunctionContext* context, + const doris_udf::DecimalV2Val& val, int num_args, + const doris_udf::DecimalV2Val* args); + + static void set_lookup_prepare_decimalv2_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static void set_lookup_close_decimalv2_val( + doris_udf::FunctionContext* ctx, doris_udf::FunctionContext::FunctionStateScope scope); + + static doris_udf::BooleanVal in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::DecimalV2Val& val, int num_args, + const doris_udf::DecimalV2Val* args); + + static doris_udf::BooleanVal not_in_set_lookup(doris_udf::FunctionContext* context, + const doris_udf::DecimalV2Val& val, int num_args, + const doris_udf::DecimalV2Val* args); + + /* added by lide */ + IN_FUNCTIONS_STMT(LargeIntVal, __int128, large_int_val) + +private: + friend class InPredicateBenchmark; + + enum Strategy { + /// Indicates we should use SetLookUp(). + SET_LOOKUP, + /// Indicates we should use Iterate(). + ITERATE + }; + + template <typename SetType> + struct SetLookupState { + /// If true, there is at least one nullptr constant in the IN list. + bool contains_null; + + /// The set of all non-nullptr constant values in the IN list. + /// Note: std::unordered_set and std::binary_search performed worse based on the + /// in-predicate-benchmark + std::set<SetType> val_set; + + /// The type of the arguments + const FunctionContext::TypeDesc* type; + }; + + /// The templated function that provides the implementation for all the In() and NotIn() + /// functions. + template <typename T, typename SetType, bool not_in, Strategy strategy> + static inline doris_udf::BooleanVal templated_in(doris_udf::FunctionContext* context, + const T& val, int num_args, const T* args); + + /// Initializes an SetLookupState in ctx. + template <typename T, typename SetType> + static void set_lookup_prepare(FunctionContext* ctx, FunctionContext::FunctionStateScope scope); + + template <typename SetType> + static void set_lookup_close(FunctionContext* ctx, FunctionContext::FunctionStateScope scope); + + /// Looks up v in state->val_set. + template <typename T, typename SetType> + static BooleanVal set_lookup(SetLookupState<SetType>* state, const T& v); + + /// 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); +}; + +} // namespace doris + +#endif --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org