From beb337fe8c771c0ac0bdda3c2f7eaf4a0b8c3e51 Mon Sep 17 00:00:00 2001 From: xufei Date: Tue, 31 Aug 2021 16:40:12 +0800 Subject: [PATCH] This is an automated cherry-pick of #2808 Signed-off-by: ti-chi-bot --- .../Coprocessor/DAGExpressionAnalyzer.cpp | 532 +++++++++++++++++- .../function_collator.test | 15 + 2 files changed, 529 insertions(+), 18 deletions(-) create mode 100644 tests/tidb-ci/new_collation_fullstack/function_collator.test diff --git a/dbms/src/Flash/Coprocessor/DAGExpressionAnalyzer.cpp b/dbms/src/Flash/Coprocessor/DAGExpressionAnalyzer.cpp index 78dd014b19a..8d9c9d3c2a9 100644 --- a/dbms/src/Flash/Coprocessor/DAGExpressionAnalyzer.cpp +++ b/dbms/src/Flash/Coprocessor/DAGExpressionAnalyzer.cpp @@ -1,4 +1,9 @@ #include +<<<<<<< HEAD +======= +#include +#include +>>>>>>> e2309433c (function result name should contain collator info (#2808)) #include #include #include @@ -22,15 +27,15 @@ namespace DB { - namespace ErrorCodes { extern const int COP_BAD_DAG_REQUEST; extern const int UNSUPPORTED_METHOD; } // namespace ErrorCodes -static String genFuncString(const String & func_name, const Names & argument_names) +static String genFuncString(const String & func_name, const Names & argument_names, const TiDB::TiDBCollators & collators) { + assert(!collators.empty()); std::stringstream ss; ss << func_name << "("; bool first = true; @@ -46,7 +51,15 @@ static String genFuncString(const String & func_name, const Names & argument_nam } ss << argument_name; } - ss << ") "; + ss << ")_collator"; + for (const auto & collator : collators) + { + if (collator == nullptr) + ss << "_0"; + else + ss << "_" << collator->getCollatorId(); + } + ss << " "; return ss.str(); } @@ -160,12 +173,86 @@ static String buildLogicalFunction(DAGExpressionAnalyzer * analyzer, const tipb: return analyzer->applyFunction(func_name, argument_names, actions, getCollatorFromExpr(expr)); } +<<<<<<< HEAD +======= +// left(str,len) = substrUTF8(str,1,len) +static String buildLeftUTF8Function(DAGExpressionAnalyzer * analyzer, const tipb::Expr & expr, ExpressionActionsPtr & actions) +{ + const String & func_name = "substringUTF8"; + Names argument_names; + + // the first parameter: str + String str = analyzer->getActions(expr.children()[0], actions, false); + argument_names.push_back(str); + + // the second parameter: const(1) + auto const_one = tipb::Expr(); + constructInt64LiteralTiExpr(const_one, 1); + auto col_const_one = analyzer->getActions(const_one, actions, false); + argument_names.push_back(col_const_one); + + // the third parameter: len + String name = analyzer->getActions(expr.children()[1], actions, false); + argument_names.push_back(name); + + return analyzer->applyFunction(func_name, argument_names, actions, getCollatorFromExpr(expr)); +} + +static String buildTupleFunctionForGroupConcat( + DAGExpressionAnalyzer * analyzer, + const tipb::Expr & expr, + SortDescription & sort_desc, + NamesAndTypes & names_and_types, + TiDB::TiDBCollators & collators, + ExpressionActionsPtr & actions) +{ + const String & func_name = "tuple"; + Names argument_names; + + /// add the first N-1 expr into the tuple + int child_size = expr.children_size() - 1; + for (auto i = 0; i < child_size; ++i) + { + auto & child = expr.children(i); + String name = analyzer->getActions(child, actions, false); + argument_names.push_back(name); + auto type = actions->getSampleBlock().getByName(name).type; + names_and_types.emplace_back(name, type); + if (removeNullable(type)->isString()) + collators.push_back(getCollatorFromExpr(expr.children(i))); + else + collators.push_back(nullptr); + } + + std::vector order_columns; + for (auto i = 0; i < expr.order_by_size(); ++i) + { + String name = analyzer->getActions(expr.order_by(i).expr(), actions); + argument_names.push_back(name); + auto type = actions->getSampleBlock().getByName(name).type; + order_columns.emplace_back(name, type); + names_and_types.emplace_back(name, type); + if (removeNullable(type)->isString()) + collators.push_back(getCollatorFromExpr(expr.children(i))); + else + collators.push_back(nullptr); + } + sort_desc = getSortDescription(order_columns, expr.order_by()); + + return analyzer->applyFunction(func_name, argument_names, actions, getCollatorFromExpr(expr)); +} + +>>>>>>> e2309433c (function result name should contain collator info (#2808)) static const String tidb_cast_name = "tidb_cast"; -static String buildCastFunctionInternal(DAGExpressionAnalyzer * analyzer, const Names & argument_names, bool in_union, - const tipb::FieldType & field_type, ExpressionActionsPtr & actions) +static String buildCastFunctionInternal( + DAGExpressionAnalyzer * analyzer, + const Names & argument_names, + bool in_union, + const tipb::FieldType & field_type, + ExpressionActionsPtr & actions) { - String result_name = genFuncString(tidb_cast_name, argument_names); + String result_name = genFuncString(tidb_cast_name, argument_names, {nullptr}); if (actions->getSampleBlock().has(result_name)) return result_name; @@ -198,8 +285,39 @@ static String buildCastFunction(DAGExpressionAnalyzer * analyzer, const tipb::Ex return buildCastFunctionInternal(analyzer, {name, type_expr_name}, false, expr.field_type(), actions); } +<<<<<<< HEAD static String buildDateAddFunction(DAGExpressionAnalyzer * analyzer, const tipb::Expr & expr, ExpressionActionsPtr & actions) { +======= +struct DateAdd +{ + static constexpr auto name = "date_add"; + static const std::unordered_map unit_to_func_name_map; +}; +const std::unordered_map DateAdd::unit_to_func_name_map + = { + {"DAY", "addDays"}, + {"WEEK", "addWeeks"}, + {"MONTH", "addMonths"}, + {"YEAR", "addYears"}, + {"HOUR", "addHours"}, + {"MINUTE", "addMinutes"}, + {"SECOND", "addSeconds"}}; +struct DateSub +{ + static constexpr auto name = "date_sub"; + static const std::unordered_map unit_to_func_name_map; +}; +const std::unordered_map DateSub::unit_to_func_name_map + = { + {"DAY", "subtractDays"}, + {"WEEK", "subtractWeeks"}, + {"MONTH", "subtractMonths"}, + {"YEAR", "subtractYears"}, + {"HOUR", "subtractHours"}, + {"MINUTE", "subtractMinutes"}, + {"SECOND", "subtractSeconds"}}; +>>>>>>> e2309433c (function result name should contain collator info (#2808)) static const std::unordered_map unit_to_func_name_map({{"DAY", "addDays"}, {"WEEK", "addWeeks"}, {"MONTH", "addMonths"}, {"YEAR", "addYears"}, {"HOUR", "addHours"}, {"MINUTE", "addMinutes"}, {"SECOND", "addSeconds"}}); @@ -211,12 +329,25 @@ static String buildDateAddFunction(DAGExpressionAnalyzer * analyzer, const tipb: String delta_column = analyzer->getActions(expr.children(1), actions); if (expr.children(2).tp() != tipb::ExprType::String) { +<<<<<<< HEAD throw TiFlashException("3rd argument of date add function must be string literal", Errors::Coprocessor::BadRequest); } String unit = expr.children(2).val(); if (unit_to_func_name_map.find(unit) == unit_to_func_name_map.end()) throw TiFlashException("date_add does not support unit " + unit + " yet.", Errors::Coprocessor::Unimplemented); String func_name = unit_to_func_name_map.find(unit)->second; +======= + throw TiFlashException( + std::string() + "3rd argument of " + Impl::name + " function must be string literal", + Errors::Coprocessor::BadRequest); + } + String unit = expr.children(2).val(); + if (Impl::unit_to_func_name_map.find(unit) == Impl::unit_to_func_name_map.end()) + throw TiFlashException( + std::string() + Impl::name + " function does not support unit " + unit + " yet.", + Errors::Coprocessor::Unimplemented); + String func_name = Impl::unit_to_func_name_map.find(unit)->second; +>>>>>>> e2309433c (function result name should contain collator info (#2808)) const auto & date_column_type = removeNullable(actions->getSampleBlock().getByName(date_column).type); if (!date_column_type->isDateOrDateTime()) { @@ -282,6 +413,7 @@ static String buildFunction(DAGExpressionAnalyzer * analyzer, const tipb::Expr & } static std::unordered_map> +<<<<<<< HEAD function_builder_map({ {"in", buildInFunction}, {"notIn", buildInFunction}, @@ -301,15 +433,209 @@ static std::unordered_map}, + {"date_sub", buildDateAddOrSubFunction}, + {"tidbRound", buildRoundFunction}}); +>>>>>>> e2309433c (function result name should contain collator info (#2808)) DAGExpressionAnalyzer::DAGExpressionAnalyzer(std::vector && source_columns_, const Context & context_) - : source_columns(std::move(source_columns_)), context(context_), after_agg(false), implicit_cast_count(0) + : source_columns(std::move(source_columns_)) + , context(context_) + , after_agg(false) + , implicit_cast_count(0) { settings = context.getSettings(); } +<<<<<<< HEAD void DAGExpressionAnalyzer::appendAggregation(ExpressionActionsChain & chain, const tipb::Aggregation & agg, Names & aggregation_keys, TiDB::TiDBCollators & collators, AggregateDescriptions & aggregate_descriptions, bool group_by_collation_sensitive) +======= +DAGExpressionAnalyzer::DAGExpressionAnalyzer(std::vector & source_columns_, const Context & context_) + : source_columns(source_columns_) + , context(context_) + , after_agg(false) + , implicit_cast_count(0) +{ + settings = context.getSettings(); +} + +void DAGExpressionAnalyzer::buildGroupConcat( + const tipb::Expr & expr, + ExpressionActionsChain::Step & step, + const String & agg_func_name, + AggregateDescriptions & aggregate_descriptions, + bool result_is_nullable) +{ + AggregateDescription aggregate; + /// the last parametric is the separator + auto child_size = expr.children_size() - 1; + NamesAndTypes all_columns_names_and_types; + String delimiter = ""; + SortDescription sort_description; + bool only_one_column = true; + TiDB::TiDBCollators arg_collators; + String arg_name; + + /// more than one args will be combined to one + DataTypes types(1); + aggregate.argument_names.resize(1); + if (child_size == 1 && expr.order_by_size() == 0) + { + /// only one arg + arg_name = getActions(expr.children(0), step.actions); + types[0] = step.actions->getSampleBlock().getByName(arg_name).type; + all_columns_names_and_types.emplace_back(arg_name, types[0]); + if (removeNullable(types[0])->isString()) + arg_collators.push_back(getCollatorFromExpr(expr.children(0))); + else + arg_collators.push_back(nullptr); + } + else + { + /// args... -> tuple(args...) + arg_name = buildTupleFunctionForGroupConcat(this, expr, sort_description, all_columns_names_and_types, arg_collators, step.actions); + only_one_column = false; + types[0] = step.actions->getSampleBlock().getByName(arg_name).type; + } + aggregate.argument_names[0] = arg_name; + step.required_output.push_back(arg_name); + + /// the separator + arg_name = getActions(expr.children(child_size), step.actions); + if (expr.children(child_size).tp() == tipb::String) + { + const ColumnConst * col_delim + = checkAndGetColumnConstStringOrFixedString(step.actions->getSampleBlock().getByName(arg_name).column.get()); + if (col_delim == nullptr) + { + throw Exception("the separator of group concat should not be invalid!"); + } + delimiter = col_delim->getValue(); + } + + /// return directly if the agg is duplicated + String func_string = genFuncString(agg_func_name, aggregate.argument_names, arg_collators); + for (const auto & pre_agg : aggregate_descriptions) + { + if (pre_agg.column_name == func_string) + { + aggregated_columns.emplace_back(func_string, pre_agg.function->getReturnType()); + return; + } + } + + aggregate.column_name = func_string; + aggregate.parameters = Array(); + /// if there is group by clause, there is no need to consider the empty input case + aggregate.function = AggregateFunctionFactory::instance().get(agg_func_name, types, {}, 0, result_is_nullable); + + /// TODO(FZH) deliver these arguments through aggregate.parameters of Array() type to keep the same code fashion, the special arguments + /// sort_description, all_columns_names_and_types can be set like the way of collators + + /// group_concat_max_length + UInt64 max_len = decodeDAGUInt64(expr.val()); + + int number_of_arguments = all_columns_names_and_types.size() - sort_description.size(); + for (int num = 0; num < number_of_arguments && !result_is_nullable; ++num) + { + if (all_columns_names_and_types[num].type->isNullable()) + { + result_is_nullable = true; + } + } + if (result_is_nullable) + { + if (only_one_column) + { + aggregate.function = std::make_shared>( + aggregate.function, + types, + delimiter, + max_len, + sort_description, + all_columns_names_and_types, + arg_collators, + expr.has_distinct()); + } + else + { + aggregate.function = std::make_shared>( + aggregate.function, + types, + delimiter, + max_len, + sort_description, + all_columns_names_and_types, + arg_collators, + expr.has_distinct()); + } + } + else + { + if (only_one_column) + { + aggregate.function = std::make_shared>( + aggregate.function, + types, + delimiter, + max_len, + sort_description, + all_columns_names_and_types, + arg_collators, + expr.has_distinct()); + } + else + { + aggregate.function = std::make_shared>( + aggregate.function, + types, + delimiter, + max_len, + sort_description, + all_columns_names_and_types, + arg_collators, + expr.has_distinct()); + } + } + + aggregate_descriptions.push_back(aggregate); + DataTypePtr result_type = aggregate.function->getReturnType(); + // this is a temp result since implicit cast maybe added on these aggregated_columns + aggregated_columns.emplace_back(func_string, result_type); +} + + +extern const String CountSecondStage; + +void DAGExpressionAnalyzer::appendAggregation( + ExpressionActionsChain & chain, + const tipb::Aggregation & agg, + Names & aggregation_keys, + TiDB::TiDBCollators & collators, + AggregateDescriptions & aggregate_descriptions, + bool group_by_collation_sensitive) +>>>>>>> e2309433c (function result name should contain collator info (#2808)) { if (agg.group_by_size() == 0 && agg.agg_func_size() == 0) { @@ -321,7 +647,30 @@ void DAGExpressionAnalyzer::appendAggregation(ExpressionActionsChain & chain, co for (const tipb::Expr & expr : agg.agg_func()) { +<<<<<<< HEAD const String & agg_func_name = getAggFunctionName(expr); +======= + String agg_func_name = getAggFunctionName(expr); + const String agg_func_name_lowercase = Poco::toLower(agg_func_name); + if (expr.has_distinct() && agg_func_name_lowercase == "countdistinct") + { + agg_func_name = settings.count_distinct_implementation; + } + if (agg.group_by_size() == 0 && agg_func_name == "sum" && expr.has_field_type() + && !getDataTypeByFieldType(expr.field_type())->isNullable()) + { + /// this is a little hack: if the query does not have group by column, and the result of sum is not nullable, then the sum + /// must be the second stage for count, in this case we should return 0 instead of null if the input is empty. + agg_func_name = CountSecondStage; + } + + if (expr.tp() == tipb::ExprType::GroupConcat) + { + buildGroupConcat(expr, step, agg_func_name, aggregate_descriptions, agg.group_by_size() == 0); + continue; + } + +>>>>>>> e2309433c (function result name should contain collator info (#2808)) AggregateDescription aggregate; DataTypes types(expr.children_size()); aggregate.argument_names.resize(expr.children_size()); @@ -332,7 +681,7 @@ void DAGExpressionAnalyzer::appendAggregation(ExpressionActionsChain & chain, co aggregate.argument_names[i] = arg_name; step.required_output.push_back(arg_name); } - String func_string = genFuncString(agg_func_name, aggregate.argument_names); + String func_string = genFuncString(agg_func_name, aggregate.argument_names, arg_collators); bool duplicate = false; for (const auto & pre_agg : aggregate_descriptions) { @@ -386,7 +735,7 @@ void DAGExpressionAnalyzer::appendAggregation(ExpressionActionsChain & chain, co types[0] = type; aggregate.argument_names[0] = name; - String func_string = genFuncString(agg_func_name, aggregate.argument_names); + String func_string = genFuncString(agg_func_name, aggregate.argument_names, arg_collators); bool duplicate = false; for (const auto & pre_agg : aggregate_descriptions) { @@ -429,9 +778,16 @@ bool isUInt8Type(const DataTypePtr & type) } String DAGExpressionAnalyzer::applyFunction( +<<<<<<< HEAD const String & func_name, const Names & arg_names, ExpressionActionsPtr & actions, std::shared_ptr collator) +======= + const String & func_name, + const Names & arg_names, + ExpressionActionsPtr & actions, + const TiDB::TiDBCollatorPtr & collator) +>>>>>>> e2309433c (function result name should contain collator info (#2808)) { - String result_name = genFuncString(func_name, arg_names); + String result_name = genFuncString(func_name, arg_names, {collator}); if (actions->getSampleBlock().has(result_name)) return result_name; const FunctionBuilderPtr & function_builder = FunctionFactory::instance().get(func_name, context); @@ -441,7 +797,9 @@ String DAGExpressionAnalyzer::applyFunction( } void DAGExpressionAnalyzer::appendWhere( - ExpressionActionsChain & chain, const std::vector & conditions, String & filter_column_name) + ExpressionActionsChain & chain, + const std::vector & conditions, + String & filter_column_name) { initChain(chain, getCurrentInputColumns()); ExpressionActionsChain::Step & last_step = chain.steps.back(); @@ -528,7 +886,9 @@ String DAGExpressionAnalyzer::convertToUInt8(ExpressionActionsPtr & actions, con } void DAGExpressionAnalyzer::appendOrderBy( - ExpressionActionsChain & chain, const tipb::TopN & topN, std::vector & order_columns) + ExpressionActionsChain & chain, + const tipb::TopN & topN, + std::vector & order_columns) { if (topN.order_by_size() == 0) { @@ -568,7 +928,10 @@ void constructTZExpr(tipb::Expr & tz_expr, const TimezoneInfo & dag_timezone_inf } String DAGExpressionAnalyzer::appendTimeZoneCast( - const String & tz_col, const String & ts_col, const String & func_name, ExpressionActionsPtr & actions) + const String & tz_col, + const String & ts_col, + const String & func_name, + ExpressionActionsPtr & actions) { String cast_expr_name = applyFunction(func_name, {ts_col, tz_col}, actions, nullptr); return cast_expr_name; @@ -614,15 +977,29 @@ bool DAGExpressionAnalyzer::appendTimeZoneCastsAfterTS(ExpressionActionsChain & } void DAGExpressionAnalyzer::appendJoin( - ExpressionActionsChain & chain, SubqueryForSet & join_query, const NamesAndTypesList & columns_added_by_join) + ExpressionActionsChain & chain, + SubqueryForSet & join_query, + const NamesAndTypesList & columns_added_by_join) { initChain(chain, getCurrentInputColumns()); ExpressionActionsPtr actions = chain.getLastActions(); actions->add(ExpressionAction::ordinaryJoin(join_query.join, columns_added_by_join)); } /// return true if some actions is needed +<<<<<<< HEAD bool DAGExpressionAnalyzer::appendJoinKey(ExpressionActionsChain & chain, const google::protobuf::RepeatedPtrField & keys, const DataTypes & key_types, Names & key_names, bool left, bool is_right_out_join) +======= +bool DAGExpressionAnalyzer::appendJoinKeyAndJoinFilters( + ExpressionActionsChain & chain, + const google::protobuf::RepeatedPtrField & keys, + const DataTypes & key_types, + Names & key_names, + bool left, + bool is_right_out_join, + const google::protobuf::RepeatedPtrField & filters, + String & filter_column_name) +>>>>>>> e2309433c (function result name should contain collator info (#2808)) { bool ret = false; initChain(chain, getCurrentInputColumns()); @@ -764,6 +1141,117 @@ void DAGExpressionAnalyzer::appendAggSelect( } } +<<<<<<< HEAD +======= +void DAGExpressionAnalyzer::generateFinalProject( + ExpressionActionsChain & chain, + const std::vector & schema, + const std::vector & output_offsets, + const String & column_prefix, + bool keep_session_timezone_info, + NamesWithAliases & final_project) +{ + if (unlikely(!keep_session_timezone_info && output_offsets.empty())) + throw Exception("Root Query block without output_offsets", ErrorCodes::LOGICAL_ERROR); + + auto & current_columns = getCurrentInputColumns(); + UniqueNameGenerator unique_name_generator; + bool need_append_timezone_cast = !keep_session_timezone_info && !context.getTimezoneInfo().is_utc_timezone; + /// TiDB can not guarantee that the field type in DAG request is accurate, so in order to make things work, + /// TiFlash will append extra type cast if needed. + bool need_append_type_cast = false; + BoolVec need_append_type_cast_vec; + if (!output_offsets.empty()) + { + /// !output_offsets.empty() means root block, we need to append type cast for root block if necessary + for (UInt32 i : output_offsets) + { + auto & actual_type = current_columns[i].type; + auto expected_type = getDataTypeByFieldType(schema[i]); + if (actual_type->getName() != expected_type->getName()) + { + need_append_type_cast = true; + need_append_type_cast_vec.push_back(true); + } + else + { + need_append_type_cast_vec.push_back(false); + } + } + } + if (!need_append_timezone_cast && !need_append_type_cast) + { + if (!output_offsets.empty()) + { + for (auto i : output_offsets) + { + final_project.emplace_back( + current_columns[i].name, + unique_name_generator.toUniqueName(column_prefix + current_columns[i].name)); + } + } + else + { + for (const auto & element : current_columns) + { + final_project.emplace_back(element.name, unique_name_generator.toUniqueName(column_prefix + element.name)); + } + } + } + else + { + /// for all the columns that need to be returned, if the type is timestamp, then convert + /// the timestamp column to UTC based, refer to appendTimeZoneCastsAfterTS for more details + initChain(chain, getCurrentInputColumns()); + ExpressionActionsChain::Step step = chain.steps.back(); + + tipb::Expr tz_expr; + constructTZExpr(tz_expr, context.getTimezoneInfo(), false); + String tz_col; + String tz_cast_func_name = context.getTimezoneInfo().is_name_based ? "ConvertTimeZoneToUTC" : "ConvertTimeZoneByOffset"; + std::vector casted(schema.size(), 0); + std::unordered_map casted_name_map; + + for (size_t index = 0; index < output_offsets.size(); index++) + { + UInt32 i = output_offsets[index]; + if ((need_append_timezone_cast && schema[i].tp() == TiDB::TypeTimestamp) || need_append_type_cast_vec[index]) + { + const auto & it = casted_name_map.find(current_columns[i].name); + if (it == casted_name_map.end()) + { + /// first add timestamp cast + String updated_name = current_columns[i].name; + if (need_append_timezone_cast && schema[i].tp() == TiDB::TypeTimestamp) + { + if (tz_col.length() == 0) + tz_col = getActions(tz_expr, step.actions); + updated_name = appendTimeZoneCast(tz_col, current_columns[i].name, tz_cast_func_name, step.actions); + } + /// then add type cast + if (need_append_type_cast_vec[index]) + { + updated_name = appendCast(getDataTypeByFieldType(schema[i]), step.actions, updated_name); + } + final_project.emplace_back(updated_name, unique_name_generator.toUniqueName(column_prefix + updated_name)); + casted_name_map[current_columns[i].name] = updated_name; + } + else + { + final_project.emplace_back(it->second, unique_name_generator.toUniqueName(column_prefix + it->second)); + } + } + else + { + final_project.emplace_back( + current_columns[i].name, + unique_name_generator.toUniqueName(column_prefix + current_columns[i].name)); + } + } + } +} + +>>>>>>> e2309433c (function result name should contain collator info (#2808)) /** * when force_uint8 is false, alignReturnType align the data type in tiflash with the data type in dag request, otherwise * always convert the return type to uint8 or nullable(uint8) @@ -774,7 +1262,10 @@ void DAGExpressionAnalyzer::appendAggSelect( * @return */ String DAGExpressionAnalyzer::alignReturnType( - const tipb::Expr & expr, ExpressionActionsPtr & actions, const String & expr_name, bool force_uint8) + const tipb::Expr & expr, + ExpressionActionsPtr & actions, + const String & expr_name, + bool force_uint8) { DataTypePtr orig_type = actions->getSampleBlock().getByName(expr_name).type; if (force_uint8 && isUInt8Type(orig_type)) @@ -798,7 +1289,10 @@ String DAGExpressionAnalyzer::appendCast(const DataTypePtr & target_type, Expres } String DAGExpressionAnalyzer::appendCastIfNeeded( - const tipb::Expr & expr, ExpressionActionsPtr & actions, const String & expr_name, bool explicit_cast) + const tipb::Expr & expr, + ExpressionActionsPtr & actions, + const String & expr_name, + bool explicit_cast) { if (!isFunctionExpr(expr)) return expr_name; @@ -813,7 +1307,6 @@ String DAGExpressionAnalyzer::appendCastIfNeeded( DataTypePtr actual_type = actions->getSampleBlock().getByName(expr_name).type; if (expected_type->getName() != actual_type->getName()) { - implicit_cast_count += !explicit_cast; return appendCast(expected_type, actions, expr_name); } @@ -826,7 +1319,10 @@ String DAGExpressionAnalyzer::appendCastIfNeeded( } void DAGExpressionAnalyzer::makeExplicitSet( - const tipb::Expr & expr, const Block & sample_block, bool create_ordered_set, const String & left_arg_name) + const tipb::Expr & expr, + const Block & sample_block, + bool create_ordered_set, + const String & left_arg_name) { if (prepared_sets.count(&expr)) { diff --git a/tests/tidb-ci/new_collation_fullstack/function_collator.test b/tests/tidb-ci/new_collation_fullstack/function_collator.test new file mode 100644 index 00000000000..a4c0935d785 --- /dev/null +++ b/tests/tidb-ci/new_collation_fullstack/function_collator.test @@ -0,0 +1,15 @@ +mysql> drop table if exists test.t1 +mysql> drop table if exists test.t2 +mysql> create table test.t1(col_varchar_20_key_signed varchar(20) COLLATE utf8mb4_general_ci, col_varbinary_20_key_signed varbinary(20), col_varbinary_20_undef_signed varbinary(20)); +mysql> create table test.t2(col_char_20_key_signed char(20) COLLATE utf8mb4_general_ci, col_varchar_20_undef_signed varchar(20) COLLATE utf8mb4_general_ci); +mysql> alter table test.t1 set tiflash replica 1 +mysql> alter table test.t2 set tiflash replica 1 +mysql> insert into test.t1 values('Abc',0x62,0x616263); +mysql> insert into test.t2 values('abc','b'); +func> wait_table test t1 +func> wait_table test t2 + +mysql> set session tidb_enforce_mpp=1; select * from test.t1 where t1.col_varchar_20_key_signed not in (select col_char_20_key_signed from test.t2 where t1.col_varchar_20_key_signed not in ( t1.col_varbinary_20_key_signed, t1.col_varbinary_20_undef_signed,col_varchar_20_undef_signed,col_char_20_key_signed)); + +mysql> drop table if exists test.t1; +mysql> drop table if exists test.t2;