From 42b40557b3ec760b9996ca6a798f8351119f2f22 Mon Sep 17 00:00:00 2001 From: SeaRise Date: Mon, 25 Jul 2022 15:35:10 +0800 Subject: [PATCH] Planner: support table scan (#5335) ref pingcap/tiflash#4739 --- .../Coprocessor/DAGQueryBlockInterpreter.cpp | 2 +- .../Flash/Coprocessor/GenSchemaAndColumn.cpp | 33 +- .../Flash/Coprocessor/GenSchemaAndColumn.h | 3 +- dbms/src/Flash/Coprocessor/PushDownFilter.cpp | 9 +- dbms/src/Flash/Coprocessor/PushDownFilter.h | 10 +- dbms/src/Flash/Planner/PhysicalPlan.cpp | 38 +- dbms/src/Flash/Planner/PlanType.cpp | 4 + dbms/src/Flash/Planner/PlanType.h | 2 + dbms/src/Flash/Planner/Planner.cpp | 19 +- .../plans/PhysicalMockExchangeReceiver.cpp | 46 +- .../plans/PhysicalMockExchangeReceiver.h | 6 + .../Planner/plans/PhysicalMockTableScan.cpp | 108 +++ .../Planner/plans/PhysicalMockTableScan.h | 56 ++ .../Flash/Planner/plans/PhysicalTableScan.cpp | 113 +++ .../Flash/Planner/plans/PhysicalTableScan.h | 55 ++ .../Planner/tests/gtest_physical_plan.cpp | 17 + .../Flash/tests/gtest_planner_interpreter.cpp | 151 ++-- dbms/src/Storages/Transaction/TiDB.cpp | 13 + dbms/src/Storages/Transaction/TiDB.h | 2 + .../fullstack-test2/dml/test_table_scan.test | 728 ++++++++++++++++++ 20 files changed, 1304 insertions(+), 111 deletions(-) create mode 100644 dbms/src/Flash/Planner/plans/PhysicalMockTableScan.cpp create mode 100644 dbms/src/Flash/Planner/plans/PhysicalMockTableScan.h create mode 100644 dbms/src/Flash/Planner/plans/PhysicalTableScan.cpp create mode 100644 dbms/src/Flash/Planner/plans/PhysicalTableScan.h create mode 100644 tests/fullstack-test2/dml/test_table_scan.test diff --git a/dbms/src/Flash/Coprocessor/DAGQueryBlockInterpreter.cpp b/dbms/src/Flash/Coprocessor/DAGQueryBlockInterpreter.cpp index 7fa32c316a1..8a86d8ae75a 100644 --- a/dbms/src/Flash/Coprocessor/DAGQueryBlockInterpreter.cpp +++ b/dbms/src/Flash/Coprocessor/DAGQueryBlockInterpreter.cpp @@ -161,7 +161,7 @@ void DAGQueryBlockInterpreter::handleMockTableScan(const TiDBTableScan & table_s { if (context.getDAGContext()->columnsForTestEmpty() || context.getDAGContext()->columnsForTest(table_scan.getTableScanExecutorID()).empty()) { - auto names_and_types = genNamesAndTypes(table_scan); + auto names_and_types = genNamesAndTypes(table_scan, "mock_table_scan"); auto columns_with_type_and_name = getColumnWithTypeAndName(names_and_types); analyzer = std::make_unique(std::move(names_and_types), context); for (size_t i = 0; i < max_streams; ++i) diff --git a/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.cpp b/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.cpp index efb8a08f1d8..56d1ed643c2 100644 --- a/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.cpp +++ b/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.cpp @@ -11,34 +11,49 @@ // 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 #include +#include #include namespace DB { -NamesAndTypes genNamesAndTypes(const TiDBTableScan & table_scan) +namespace +{ +DataTypePtr getPkType(const ColumnInfo & column_info) +{ + const auto & pk_data_type = getDataTypeByColumnInfoForComputingLayer(column_info); + /// primary key type must be tidb_pk_column_int_type or tidb_pk_column_string_type. + if (unlikely(!pk_data_type->equals(*MutableSupport::tidb_pk_column_int_type) && !pk_data_type->equals(*MutableSupport::tidb_pk_column_string_type))) + throw Exception( + fmt::format( + "Actual pk_data_type {} is not {} or {}", + pk_data_type->getName(), + MutableSupport::tidb_pk_column_int_type->getName(), + MutableSupport::tidb_pk_column_string_type->getName()), + ErrorCodes::LOGICAL_ERROR); + return pk_data_type; +} +} // namespace + +NamesAndTypes genNamesAndTypes(const TiDBTableScan & table_scan, const StringRef & column_prefix) { NamesAndTypes names_and_types; names_and_types.reserve(table_scan.getColumnSize()); for (Int32 i = 0; i < table_scan.getColumnSize(); ++i) { - TiDB::ColumnInfo column_info; - const auto & ci = table_scan.getColumns()[i]; - column_info.tp = static_cast(ci.tp()); - column_info.id = ci.column_id(); - + auto column_info = TiDB::toTiDBColumnInfo(table_scan.getColumns()[i]); switch (column_info.id) { case TiDBPkColumnID: - // TODO: need to check if the type of pk_handle_columns matches the type that used in delta merge tree. - names_and_types.emplace_back(MutableSupport::tidb_pk_column_name, getDataTypeByColumnInfoForComputingLayer(column_info)); + names_and_types.emplace_back(MutableSupport::tidb_pk_column_name, getPkType(column_info)); break; case ExtraTableIDColumnID: names_and_types.emplace_back(MutableSupport::extra_table_id_column_name, MutableSupport::extra_table_id_column_type); break; default: - names_and_types.emplace_back(fmt::format("mock_table_scan_{}", i), getDataTypeByColumnInfoForComputingLayer(column_info)); + names_and_types.emplace_back(fmt::format("{}_{}", column_prefix, i), getDataTypeByColumnInfoForComputingLayer(column_info)); } } return names_and_types; diff --git a/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.h b/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.h index 96f202d800e..cdd032b3c8c 100644 --- a/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.h +++ b/dbms/src/Flash/Coprocessor/GenSchemaAndColumn.h @@ -19,10 +19,11 @@ #include #include #include +#include namespace DB { -NamesAndTypes genNamesAndTypes(const TiDBTableScan & table_scan); +NamesAndTypes genNamesAndTypes(const TiDBTableScan & table_scan, const StringRef & column_prefix); ColumnsWithTypeAndName getColumnWithTypeAndName(const NamesAndTypes & names_and_types); NamesAndTypes toNamesAndTypes(const DAGSchema & dag_schema); } // namespace DB diff --git a/dbms/src/Flash/Coprocessor/PushDownFilter.cpp b/dbms/src/Flash/Coprocessor/PushDownFilter.cpp index bc08d9ac8e3..26da298ba9c 100644 --- a/dbms/src/Flash/Coprocessor/PushDownFilter.cpp +++ b/dbms/src/Flash/Coprocessor/PushDownFilter.cpp @@ -56,10 +56,15 @@ PushDownFilter PushDownFilter::toPushDownFilter(const String & executor_id, cons return {"", {}}; } + return toPushDownFilter(executor_id, executor->selection()); +} + +PushDownFilter PushDownFilter::toPushDownFilter(const String & executor_id, const tipb::Selection & selection) +{ std::vector conditions; - for (const auto & condition : executor->selection().conditions()) + for (const auto & condition : selection.conditions()) conditions.push_back(&condition); return {executor_id, conditions}; } -} // namespace DB \ No newline at end of file +} // namespace DB diff --git a/dbms/src/Flash/Coprocessor/PushDownFilter.h b/dbms/src/Flash/Coprocessor/PushDownFilter.h index 9645264a71c..01d59d9056a 100644 --- a/dbms/src/Flash/Coprocessor/PushDownFilter.h +++ b/dbms/src/Flash/Coprocessor/PushDownFilter.h @@ -25,6 +25,10 @@ struct PushDownFilter { static PushDownFilter toPushDownFilter(const String & executor_id, const tipb::Executor * executor); + static PushDownFilter toPushDownFilter(const String & executor_id, const tipb::Selection & selection); + + PushDownFilter() = default; + PushDownFilter( const String & executor_id_, const std::vector & conditions_); @@ -33,7 +37,7 @@ struct PushDownFilter tipb::Executor * constructSelectionForRemoteRead(tipb::Executor * mutable_executor) const; - String executor_id; - std::vector conditions; + String executor_id{}; + std::vector conditions{}; }; -} // namespace DB \ No newline at end of file +} // namespace DB diff --git a/dbms/src/Flash/Planner/PhysicalPlan.cpp b/dbms/src/Flash/Planner/PhysicalPlan.cpp index db97423772b..745abff296e 100644 --- a/dbms/src/Flash/Planner/PhysicalPlan.cpp +++ b/dbms/src/Flash/Planner/PhysicalPlan.cpp @@ -24,14 +24,33 @@ #include #include #include +#include #include #include +#include #include #include #include namespace DB { +namespace +{ +bool pushDownSelection(const PhysicalPlanNodePtr & plan, const String & executor_id, const tipb::Selection & selection) +{ + if (plan->tp() == PlanType::TableScan) + { + auto physical_table_scan = std::static_pointer_cast(plan); + if (!physical_table_scan->hasPushDownFilter()) + { + physical_table_scan->pushDownFilter(executor_id, selection); + return true; + } + } + return false; +} +} // namespace + void PhysicalPlan::build(const tipb::DAGRequest * dag_request) { assert(dag_request); @@ -56,8 +75,14 @@ void PhysicalPlan::build(const String & executor_id, const tipb::Executor * exec pushBack(PhysicalTopN::build(context, executor_id, log, executor->topn(), popBack())); break; case tipb::ExecType::TypeSelection: - pushBack(PhysicalFilter::build(context, executor_id, log, executor->selection(), popBack())); + { + auto child = popBack(); + if (pushDownSelection(child, executor_id, executor->selection())) + pushBack(child); + else + pushBack(PhysicalFilter::build(context, executor_id, log, executor->selection(), child)); break; + } case tipb::ExecType::TypeAggregation: case tipb::ExecType::TypeStreamAgg: pushBack(PhysicalAggregation::build(context, executor_id, log, executor->aggregation(), popBack())); @@ -81,6 +106,17 @@ void PhysicalPlan::build(const String & executor_id, const tipb::Executor * exec case tipb::ExecType::TypeProjection: pushBack(PhysicalProjection::build(context, executor_id, log, executor->projection(), popBack())); break; + case tipb::ExecType::TypeTableScan: + case tipb::ExecType::TypePartitionTableScan: + { + TiDBTableScan table_scan(executor, executor_id, dagContext()); + if (unlikely(dagContext().isTest())) + pushBack(PhysicalMockTableScan::build(context, executor_id, log, table_scan)); + else + pushBack(PhysicalTableScan::build(executor_id, log, table_scan)); + dagContext().table_scan_executor_id = executor_id; + break; + } default: throw TiFlashException(fmt::format("{} executor is not supported", executor->tp()), Errors::Planner::Unimplemented); } diff --git a/dbms/src/Flash/Planner/PlanType.cpp b/dbms/src/Flash/Planner/PlanType.cpp index e04f08d005f..5759c1a2288 100644 --- a/dbms/src/Flash/Planner/PlanType.cpp +++ b/dbms/src/Flash/Planner/PlanType.cpp @@ -41,6 +41,10 @@ String PlanType::toString() const return "MockExchangeReceiver"; case Projection: return "Projection"; + case TableScan: + return "TableScan"; + case MockTableScan: + return "MockTableScan"; default: throw TiFlashException("Unknown PlanType", Errors::Planner::Internal); } diff --git a/dbms/src/Flash/Planner/PlanType.h b/dbms/src/Flash/Planner/PlanType.h index 7cd0c28d2e8..6ef25af94f1 100644 --- a/dbms/src/Flash/Planner/PlanType.h +++ b/dbms/src/Flash/Planner/PlanType.h @@ -32,6 +32,8 @@ struct PlanType ExchangeReceiver = 7, MockExchangeReceiver = 8, Projection = 9, + TableScan = 10, + MockTableScan = 11, }; PlanTypeEnum enum_value; diff --git a/dbms/src/Flash/Planner/Planner.cpp b/dbms/src/Flash/Planner/Planner.cpp index 8aae14b9420..1481eadb905 100644 --- a/dbms/src/Flash/Planner/Planner.cpp +++ b/dbms/src/Flash/Planner/Planner.cpp @@ -24,14 +24,12 @@ namespace DB { namespace { -void analyzePhysicalPlan(Context & context, PhysicalPlan & physical_plan, const DAGQueryBlock & query_block) +void analyzePhysicalPlan(PhysicalPlan & physical_plan, const DAGQueryBlock & query_block) { assert(query_block.source); physical_plan.build(query_block.source_name, query_block.source); - // selection on table scan had been executed in table scan. - // In test mode, filter is not pushed down to table scan. - if (query_block.selection && (!query_block.isTableScanSource() || context.getDAGContext()->isTest())) + if (query_block.selection) { physical_plan.build(query_block.selection_name, query_block.selection); } @@ -92,10 +90,13 @@ bool Planner::isSupported(const DAGQueryBlock & query_block) return !enableFineGrainedShuffle(query_block.source->fine_grained_shuffle_stream_count()) && (!query_block.exchange_sender || !enableFineGrainedShuffle(query_block.exchange_sender->fine_grained_shuffle_stream_count())); }; - return query_block.source - && (query_block.source->tp() == tipb::ExecType::TypeProjection - || query_block.source->tp() == tipb::ExecType::TypeExchangeReceiver) - && disable_fine_frained_shuffle(query_block); + static auto has_supported_source = [](const DAGQueryBlock & query_block) { + return query_block.source + && (query_block.source->tp() == tipb::ExecType::TypeProjection + || query_block.source->tp() == tipb::ExecType::TypeExchangeReceiver + || query_block.isTableScanSource()); + }; + return has_supported_source(query_block) && disable_fine_frained_shuffle(query_block); } DAGContext & Planner::dagContext() const @@ -118,7 +119,7 @@ void Planner::executeImpl(DAGPipeline & pipeline) physical_plan.buildSource(input_streams); } - analyzePhysicalPlan(context, physical_plan, query_block); + analyzePhysicalPlan(physical_plan, query_block); physical_plan.outputAndOptimize(); diff --git a/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.cpp b/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.cpp index 1dc5b680937..0cab9f3ae03 100644 --- a/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.cpp +++ b/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.cpp @@ -22,18 +22,9 @@ namespace DB { -PhysicalMockExchangeReceiver::PhysicalMockExchangeReceiver( - const String & executor_id_, - const NamesAndTypes & schema_, - const String & req_id, - const Block & sample_block_, - const BlockInputStreams & mock_streams_) - : PhysicalLeaf(executor_id_, PlanType::MockExchangeReceiver, schema_, req_id) - , sample_block(sample_block_) - , mock_streams(mock_streams_) -{} - -PhysicalPlanNodePtr PhysicalMockExchangeReceiver::build( +namespace +{ +std::pair mockSchemaAndStreams( Context & context, const String & executor_id, const LoggerPtr & log, @@ -41,10 +32,14 @@ PhysicalPlanNodePtr PhysicalMockExchangeReceiver::build( { NamesAndTypes schema; BlockInputStreams mock_streams; + auto & dag_context = *context.getDAGContext(); size_t max_streams = dag_context.initialize_concurrency; + assert(max_streams > 0); + if (dag_context.columnsForTestEmpty() || dag_context.columnsForTest(executor_id).empty()) { + /// build with default blocks. for (size_t i = 0; i < max_streams; ++i) // use max_block_size / 10 to determine the mock block's size mock_streams.push_back(std::make_shared(exchange_receiver, context.getSettingsRef().max_block_size, context.getSettingsRef().max_block_size / 10)); @@ -53,13 +48,40 @@ PhysicalPlanNodePtr PhysicalMockExchangeReceiver::build( } else { + /// build from user input blocks. auto [names_and_types, mock_exchange_streams] = mockSourceStream(context, max_streams, log, executor_id); schema = std::move(names_and_types); mock_streams.insert(mock_streams.end(), mock_exchange_streams.begin(), mock_exchange_streams.end()); } + assert(!schema.empty()); assert(!mock_streams.empty()); + return {std::move(schema), std::move(mock_streams)}; +} +} // namespace + +PhysicalMockExchangeReceiver::PhysicalMockExchangeReceiver( + const String & executor_id_, + const NamesAndTypes & schema_, + const String & req_id, + const Block & sample_block_, + const BlockInputStreams & mock_streams_) + : PhysicalLeaf(executor_id_, PlanType::MockExchangeReceiver, schema_, req_id) + , sample_block(sample_block_) + , mock_streams(mock_streams_) +{} + +PhysicalPlanNodePtr PhysicalMockExchangeReceiver::build( + Context & context, + const String & executor_id, + const LoggerPtr & log, + const tipb::ExchangeReceiver & exchange_receiver) +{ + assert(context.getDAGContext()->isTest()); + + auto [schema, mock_streams] = mockSchemaAndStreams(context, executor_id, log, exchange_receiver); + auto physical_mock_exchange_receiver = std::make_shared( executor_id, schema, diff --git a/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.h b/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.h index b269ee438a7..e222ca9b8df 100644 --- a/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.h +++ b/dbms/src/Flash/Planner/plans/PhysicalMockExchangeReceiver.h @@ -20,6 +20,11 @@ namespace DB { +/** + * A physical plan node that generates MockExchangeReceiverInputStream. + * Used in gtest to test execution logic. + * Only available with `DAGContext.isTest() == true`. + */ class PhysicalMockExchangeReceiver : public PhysicalLeaf { public: @@ -43,6 +48,7 @@ class PhysicalMockExchangeReceiver : public PhysicalLeaf private: void transformImpl(DAGPipeline & pipeline, Context & /*context*/, size_t /*max_streams*/) override; +private: Block sample_block; BlockInputStreams mock_streams; diff --git a/dbms/src/Flash/Planner/plans/PhysicalMockTableScan.cpp b/dbms/src/Flash/Planner/plans/PhysicalMockTableScan.cpp new file mode 100644 index 00000000000..1ad99f24e96 --- /dev/null +++ b/dbms/src/Flash/Planner/plans/PhysicalMockTableScan.cpp @@ -0,0 +1,108 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed 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 +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ +namespace +{ +std::pair mockSchemaAndStreams( + Context & context, + const String & executor_id, + const LoggerPtr & log, + const TiDBTableScan & table_scan) +{ + NamesAndTypes schema; + BlockInputStreams mock_streams; + + auto & dag_context = *context.getDAGContext(); + size_t max_streams = dag_context.initialize_concurrency; + assert(max_streams > 0); + + if (dag_context.columnsForTestEmpty() || dag_context.columnsForTest(executor_id).empty()) + { + /// build with default blocks. + schema = genNamesAndTypes(table_scan, "mock_table_scan"); + auto columns_with_type_and_name = getColumnWithTypeAndName(schema); + for (size_t i = 0; i < max_streams; ++i) + mock_streams.emplace_back(std::make_shared(columns_with_type_and_name, context.getSettingsRef().max_block_size)); + } + else + { + /// build from user input blocks. + auto [names_and_types, mock_table_scan_streams] = mockSourceStream(context, max_streams, log, executor_id); + schema = std::move(names_and_types); + mock_streams.insert(mock_streams.end(), mock_table_scan_streams.begin(), mock_table_scan_streams.end()); + } + + assert(!schema.empty()); + assert(!mock_streams.empty()); + + return {std::move(schema), std::move(mock_streams)}; +} +} // namespace + +PhysicalMockTableScan::PhysicalMockTableScan( + const String & executor_id_, + const NamesAndTypes & schema_, + const String & req_id, + const Block & sample_block_, + const BlockInputStreams & mock_streams_) + : PhysicalLeaf(executor_id_, PlanType::MockTableScan, schema_, req_id) + , sample_block(sample_block_) + , mock_streams(mock_streams_) +{} + +PhysicalPlanNodePtr PhysicalMockTableScan::build( + Context & context, + const String & executor_id, + const LoggerPtr & log, + const TiDBTableScan & table_scan) +{ + assert(context.getDAGContext()->isTest()); + + auto [schema, mock_streams] = mockSchemaAndStreams(context, executor_id, log, table_scan); + + auto physical_mock_table_scan = std::make_shared( + executor_id, + schema, + log->identifier(), + PhysicalPlanHelper::constructBlockFromSchema(schema), + mock_streams); + return physical_mock_table_scan; +} + +void PhysicalMockTableScan::transformImpl(DAGPipeline & pipeline, Context & /*context*/, size_t /*max_streams*/) +{ + pipeline.streams.insert(pipeline.streams.end(), mock_streams.begin(), mock_streams.end()); +} + +void PhysicalMockTableScan::finalize(const Names & parent_require) +{ + FinalizeHelper::checkSchemaContainsParentRequire(schema, parent_require); +} + +const Block & PhysicalMockTableScan::getSampleBlock() const +{ + return sample_block; +} +} // namespace DB diff --git a/dbms/src/Flash/Planner/plans/PhysicalMockTableScan.h b/dbms/src/Flash/Planner/plans/PhysicalMockTableScan.h new file mode 100644 index 00000000000..f234980911f --- /dev/null +++ b/dbms/src/Flash/Planner/plans/PhysicalMockTableScan.h @@ -0,0 +1,56 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed 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. + +#pragma once + +#include +#include +#include +#include + +namespace DB +{ +/** + * A physical plan node that generates MockTableScanBlockInputStream. + * Used in gtest to test execution logic. + * Only available with `DAGContext.isTest() == true`. + */ +class PhysicalMockTableScan : public PhysicalLeaf +{ +public: + static PhysicalPlanNodePtr build( + Context & context, + const String & executor_id, + const LoggerPtr & log, + const TiDBTableScan & table_scan); + + PhysicalMockTableScan( + const String & executor_id_, + const NamesAndTypes & schema_, + const String & req_id, + const Block & sample_block_, + const BlockInputStreams & mock_streams_); + + void finalize(const Names & parent_require) override; + + const Block & getSampleBlock() const override; + +private: + void transformImpl(DAGPipeline & pipeline, Context & /*context*/, size_t /*max_streams*/) override; + + Block sample_block; + + BlockInputStreams mock_streams; +}; +} // namespace DB diff --git a/dbms/src/Flash/Planner/plans/PhysicalTableScan.cpp b/dbms/src/Flash/Planner/plans/PhysicalTableScan.cpp new file mode 100644 index 00000000000..088d7a419c1 --- /dev/null +++ b/dbms/src/Flash/Planner/plans/PhysicalTableScan.cpp @@ -0,0 +1,113 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ +PhysicalTableScan::PhysicalTableScan( + const String & executor_id_, + const NamesAndTypes & schema_, + const String & req_id, + const TiDBTableScan & tidb_table_scan_, + const Block & sample_block_) + : PhysicalLeaf(executor_id_, PlanType::TableScan, schema_, req_id) + , tidb_table_scan(tidb_table_scan_) + , sample_block(sample_block_) +{} + +PhysicalPlanNodePtr PhysicalTableScan::build( + const String & executor_id, + const LoggerPtr & log, + const TiDBTableScan & table_scan) +{ + auto schema = genNamesAndTypes(table_scan, "table_scan"); + auto physical_table_scan = std::make_shared( + executor_id, + schema, + log->identifier(), + table_scan, + PhysicalPlanHelper::constructBlockFromSchema(schema)); + return physical_table_scan; +} + +void PhysicalTableScan::transformImpl(DAGPipeline & pipeline, Context & context, size_t max_streams) +{ + assert(pipeline.streams.empty() && pipeline.streams_with_non_joined_data.empty()); + + DAGStorageInterpreter storage_interpreter(context, tidb_table_scan, push_down_filter, max_streams); + storage_interpreter.execute(pipeline); + + const auto & storage_schema = storage_interpreter.analyzer->getCurrentInputColumns(); + if (unlikely(storage_schema.size() != schema.size())) + throw TiFlashException( + fmt::format( + "Expected col num does not match actual col num {}", + schema.size(), + storage_schema.size()), + Errors::Planner::Internal); + NamesWithAliases schema_project_cols; + for (size_t i = 0; i < schema.size(); ++i) + { + if (unlikely(!schema[i].type->equals(*storage_schema[i].type))) + { + throw TiFlashException( + fmt::format( + "The type of schema col <{}, {}> does not match the type of actual col <{}, {}>", + schema[i].name, + schema[i].type->getName(), + storage_schema[i].name, + storage_schema[i].type->getName()), + Errors::Planner::Internal); + } + assert(!storage_schema[i].name.empty() && !schema[i].name.empty()); + schema_project_cols.emplace_back(storage_schema[i].name, schema[i].name); + } + /// In order to keep BlockInputStream's schema consistent with PhysicalPlan's schema. + /// It is worth noting that the column uses the name as the unique identifier in the Block, so the column name must also be consistent. + ExpressionActionsPtr schema_project = generateProjectExpressionActions(pipeline.firstStream(), context, schema_project_cols); + executeExpression(pipeline, schema_project, log, "table scan schema projection"); +} + +void PhysicalTableScan::finalize(const Names & parent_require) +{ + FinalizeHelper::checkSchemaContainsParentRequire(schema, parent_require); +} + +const Block & PhysicalTableScan::getSampleBlock() const +{ + return sample_block; +} + +void PhysicalTableScan::pushDownFilter(const String & filter_executor_id, const tipb::Selection & selection) +{ + if (unlikely(hasPushDownFilter())) + throw TiFlashException("PhysicalTableScan cannot push down more than one filter", Errors::Planner::Internal); + push_down_filter = PushDownFilter::toPushDownFilter(filter_executor_id, selection); +} + +bool PhysicalTableScan::hasPushDownFilter() const +{ + return push_down_filter.hasValue(); +} +} // namespace DB diff --git a/dbms/src/Flash/Planner/plans/PhysicalTableScan.h b/dbms/src/Flash/Planner/plans/PhysicalTableScan.h new file mode 100644 index 00000000000..826ef79d0c0 --- /dev/null +++ b/dbms/src/Flash/Planner/plans/PhysicalTableScan.h @@ -0,0 +1,55 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed 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 +#include +#include +#include + +namespace DB +{ +class PhysicalTableScan : public PhysicalLeaf +{ +public: + static PhysicalPlanNodePtr build( + const String & executor_id, + const LoggerPtr & log, + const TiDBTableScan & table_scan); + + PhysicalTableScan( + const String & executor_id_, + const NamesAndTypes & schema_, + const String & req_id, + const TiDBTableScan & tidb_table_scan_, + const Block & sample_block_); + + void finalize(const Names & parent_require) override; + + const Block & getSampleBlock() const override; + + void pushDownFilter(const String & filter_executor_id, const tipb::Selection & selection); + + bool hasPushDownFilter() const; + +private: + void transformImpl(DAGPipeline & pipeline, Context & context, size_t max_streams) override; + +private: + PushDownFilter push_down_filter; + + TiDBTableScan tidb_table_scan; + + Block sample_block; +}; +} // namespace DB diff --git a/dbms/src/Flash/Planner/tests/gtest_physical_plan.cpp b/dbms/src/Flash/Planner/tests/gtest_physical_plan.cpp index 45414b717df..9c563a67b41 100644 --- a/dbms/src/Flash/Planner/tests/gtest_physical_plan.cpp +++ b/dbms/src/Flash/Planner/tests/gtest_physical_plan.cpp @@ -221,5 +221,22 @@ MockExchangeReceiver)", } CATCH +TEST_F(PhysicalPlanTestRunner, MockTableScan) +try +{ + auto request = context.scan("test_db", "test_table") + .build(context); + + execute( + request, + /*expected_physical_plan=*/R"( + | is_record_profile_streams: true, schema: , )", + /*expected_streams=*/R"( +MockTableScan)", + {toNullableVec({"banana", {}, "banana"}), + toNullableVec({"apple", {}, "banana"})}); +} +CATCH + } // namespace tests } // namespace DB diff --git a/dbms/src/Flash/tests/gtest_planner_interpreter.cpp b/dbms/src/Flash/tests/gtest_planner_interpreter.cpp index aa4950a2b22..5ab90ead996 100644 --- a/dbms/src/Flash/tests/gtest_planner_interpreter.cpp +++ b/dbms/src/Flash/tests/gtest_planner_interpreter.cpp @@ -50,18 +50,19 @@ try { String expected = R"( Union: - SharedQuery x 10: - Expression: + Expression x 10: + SharedQuery: MergeSorting, limit = 10 Union: PartialSorting x 10: limit = 10 - Expression: - Filter: - SharedQuery: - ParallelAggregating, max_threads: 10, final: true - Expression x 10: - Filter: - MockTableScan)"; + Expression: + Filter + Expression: + SharedQuery: + ParallelAggregating, max_threads: 10, final: true + Expression x 10: + Filter + MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 10); } @@ -75,17 +76,17 @@ Union: { String expected = R"( Union: - SharedQuery x 10: - Limit, limit = 10 - Union: - Limit x 10, limit = 10 - Expression: - Expression: - Filter: + Expression x 10: + SharedQuery: + Limit, limit = 10 + Union: + Limit x 10, limit = 10 + Filter + Expression: SharedQuery: ParallelAggregating, max_threads: 10, final: true Expression x 10: - Filter: + Filter MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 10); } @@ -101,18 +102,18 @@ try .build(context); { String expected = R"( -Limit, limit = 10 - Expression: +Expression: + Limit, limit = 10 MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 1); expected = R"( Union: - SharedQuery x 5: - Limit, limit = 10 - Union: - Limit x 5, limit = 10 - Expression: + Expression x 5: + SharedQuery: + Limit, limit = 10 + Union: + Limit x 5, limit = 10 MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 5); } @@ -143,17 +144,19 @@ Union: { String expected = R"( Expression: - Aggregating - Concat - MockTableScan)"; + Expression: + Aggregating + Concat + MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 1); expected = R"( Union: Expression x 5: - SharedQuery: - ParallelAggregating, max_threads: 5, final: true - MockTableScan x 5)"; + Expression: + SharedQuery: + ParallelAggregating, max_threads: 5, final: true + MockTableScan x 5)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 5); } @@ -170,8 +173,8 @@ Expression: expected = R"( Union: - SharedQuery x 5: - Expression: + Expression x 5: + SharedQuery: MergeSorting, limit = 10 Union: PartialSorting x 5: limit = 10 @@ -185,17 +188,15 @@ Union: { String expected = R"( Expression: - Expression: - Filter: - MockTableScan)"; + Filter + MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 1); expected = R"( Union: Expression x 5: - Expression: - Filter: - MockTableScan)"; + Filter + MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 5); } @@ -213,11 +214,11 @@ Union: SharedQuery: ParallelAggregating, max_threads: 10, final: true Expression x 10: - SharedQuery: - Limit, limit = 10 - Union: - Limit x 10, limit = 10 - Expression: + Expression: + SharedQuery: + Limit, limit = 10 + Union: + Limit x 10, limit = 10 MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 10); @@ -227,8 +228,8 @@ Expression: Aggregating Concat Expression: - Limit, limit = 10 - Expression: + Expression: + Limit, limit = 10 MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 1); } @@ -246,8 +247,8 @@ Union: SharedQuery: ParallelAggregating, max_threads: 10, final: true Expression x 10: - SharedQuery: - Expression: + Expression: + SharedQuery: MergeSorting, limit = 10 Union: PartialSorting x 10: limit = 10 @@ -281,9 +282,10 @@ Union: ParallelAggregating, max_threads: 10, final: true Expression x 10: Expression: - SharedQuery: - ParallelAggregating, max_threads: 10, final: true - MockTableScan x 10)"; + Expression: + SharedQuery: + ParallelAggregating, max_threads: 10, final: true + MockTableScan x 10)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 10); expected = R"( @@ -293,9 +295,10 @@ Expression: Concat Expression: Expression: - Aggregating - Concat - MockTableScan)"; + Expression: + Aggregating + Concat + MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 1); } @@ -308,17 +311,19 @@ Expression: Union: MockExchangeSender x 10 Expression: - SharedQuery: - ParallelAggregating, max_threads: 10, final: true - MockTableScan x 10)"; + Expression: + SharedQuery: + ParallelAggregating, max_threads: 10, final: true + MockTableScan x 10)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 10); expected = R"( MockExchangeSender Expression: - Aggregating - Concat - MockTableScan)"; + Expression: + Aggregating + Concat + MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 1); } @@ -330,8 +335,8 @@ MockExchangeSender String expected = R"( Union: MockExchangeSender x 10 - SharedQuery: - Expression: + Expression: + SharedQuery: MergeSorting, limit = 10 Union: PartialSorting x 10: limit = 10 @@ -355,18 +360,18 @@ MockExchangeSender String expected = R"( Union: MockExchangeSender x 10 - SharedQuery: - Limit, limit = 10 - Union: - Limit x 10, limit = 10 - Expression: + Expression: + SharedQuery: + Limit, limit = 10 + Union: + Limit x 10, limit = 10 MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 10); expected = R"( MockExchangeSender - Limit, limit = 10 - Expression: + Expression: + Limit, limit = 10 MockTableScan)"; ASSERT_BLOCKINPUTSTREAM_EQAUL(expected, request, 1); } @@ -380,11 +385,11 @@ CreatingSets Union: HashJoinBuildBlockInputStream x 10: , join_kind = Left Expression: - SharedQuery: - Limit, limit = 1 - Union: - Limit x 10, limit = 1 - Expression: + Expression: + SharedQuery: + Limit, limit = 1 + Union: + Limit x 10, limit = 1 MockTableScan Union: Expression x 10: diff --git a/dbms/src/Storages/Transaction/TiDB.cpp b/dbms/src/Storages/Transaction/TiDB.cpp index 6d07c47f235..cd1dc583a7c 100644 --- a/dbms/src/Storages/Transaction/TiDB.cpp +++ b/dbms/src/Storages/Transaction/TiDB.cpp @@ -1170,4 +1170,17 @@ ColumnInfo fieldTypeToColumnInfo(const tipb::FieldType & field_type) return ret; } +ColumnInfo toTiDBColumnInfo(const tipb::ColumnInfo & tipb_column_info) +{ + ColumnInfo tidb_column_info; + tidb_column_info.tp = static_cast(tipb_column_info.tp()); + tidb_column_info.id = tipb_column_info.column_id(); + tidb_column_info.flag = tipb_column_info.flag(); + tidb_column_info.flen = tipb_column_info.columnlen(); + tidb_column_info.decimal = tipb_column_info.decimal(); + for (int i = 0; i < tipb_column_info.elems_size(); ++i) + tidb_column_info.elems.emplace_back(tipb_column_info.elems(i), i + 1); + return tidb_column_info; +} + } // namespace TiDB diff --git a/dbms/src/Storages/Transaction/TiDB.h b/dbms/src/Storages/Transaction/TiDB.h index a9d46b60c13..0f136786fd5 100644 --- a/dbms/src/Storages/Transaction/TiDB.h +++ b/dbms/src/Storages/Transaction/TiDB.h @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -420,6 +421,7 @@ String genJsonNull(); tipb::FieldType columnInfoToFieldType(const ColumnInfo & ci); ColumnInfo fieldTypeToColumnInfo(const tipb::FieldType & field_type); +ColumnInfo toTiDBColumnInfo(const tipb::ColumnInfo & tipb_column_info); String TiFlashModeToString(TiFlashMode tiflash_mode); TiFlashMode parseTiFlashMode(String mode_str); diff --git a/tests/fullstack-test2/dml/test_table_scan.test b/tests/fullstack-test2/dml/test_table_scan.test new file mode 100644 index 00000000000..ba234cebd6f --- /dev/null +++ b/tests/fullstack-test2/dml/test_table_scan.test @@ -0,0 +1,728 @@ +# Copyright 2022 PingCAP, Ltd. +# +# Licensed 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. + +# TINYINT +## clustered_index +mysql> drop table if exists test.t_TINYINT_CI +mysql> create table test.t_TINYINT_CI(pk TINYINT NOT NULL, col1 TINYINT, col2 TINYINT NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_TINYINT_CI values(0, NULL, 0); +mysql> alter table test.t_TINYINT_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_TINYINT_NCI +mysql> create table test.t_TINYINT_NCI(pk TINYINT NOT NULL, col1 TINYINT, col2 TINYINT NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_TINYINT_NCI values(0, NULL, 0); +mysql> alter table test.t_TINYINT_NCI set tiflash replica 1 + +# SMALLINT +## clustered_index +mysql> drop table if exists test.t_SMALLINT_CI +mysql> create table test.t_SMALLINT_CI(pk SMALLINT NOT NULL, col1 SMALLINT, col2 SMALLINT NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_SMALLINT_CI values(0, NULL, 0); +mysql> alter table test.t_SMALLINT_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_SMALLINT_NCI +mysql> create table test.t_SMALLINT_NCI(pk SMALLINT NOT NULL, col1 SMALLINT, col2 SMALLINT NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_SMALLINT_NCI values(0, NULL, 0); +mysql> alter table test.t_SMALLINT_NCI set tiflash replica 1 + +# MEDIUMINT +## clustered_index +mysql> drop table if exists test.t_MEDIUMINT_CI +mysql> create table test.t_MEDIUMINT_CI(pk MEDIUMINT NOT NULL, col1 MEDIUMINT, col2 MEDIUMINT NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_MEDIUMINT_CI values(0, NULL, 0); +mysql> alter table test.t_MEDIUMINT_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_MEDIUMINT_NCI +mysql> create table test.t_MEDIUMINT_NCI(pk MEDIUMINT NOT NULL, col1 MEDIUMINT, col2 MEDIUMINT NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_MEDIUMINT_NCI values(0, NULL, 0); +mysql> alter table test.t_MEDIUMINT_NCI set tiflash replica 1 + +# INT +## clustered_index +mysql> drop table if exists test.t_INT_CI +mysql> create table test.t_INT_CI(pk INT NOT NULL, col1 INT, col2 INT NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_INT_CI values(0, NULL, 0); +mysql> alter table test.t_INT_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_INT_NCI +mysql> create table test.t_INT_NCI(pk INT NOT NULL, col1 INT, col2 INT NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_INT_NCI values(0, NULL, 0); +mysql> alter table test.t_INT_NCI set tiflash replica 1 + +# BIGINT +## clustered_index +mysql> drop table if exists test.t_BIGINT_CI +mysql> create table test.t_BIGINT_CI(pk BIGINT NOT NULL, col1 BIGINT, col2 BIGINT NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_BIGINT_CI values(0, NULL, 0); +mysql> alter table test.t_BIGINT_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_BIGINT_NCI +mysql> create table test.t_BIGINT_NCI(pk BIGINT NOT NULL, col1 BIGINT, col2 BIGINT NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_BIGINT_NCI values(0, NULL, 0); +mysql> alter table test.t_BIGINT_NCI set tiflash replica 1 + +# FLOAT +## clustered_index +mysql> drop table if exists test.t_FLOAT_CI +mysql> create table test.t_FLOAT_CI(pk FLOAT NOT NULL, col1 FLOAT, col2 FLOAT NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_FLOAT_CI values(0.0, NULL, 0.0); +mysql> alter table test.t_FLOAT_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_FLOAT_NCI +mysql> create table test.t_FLOAT_NCI(pk FLOAT NOT NULL, col1 FLOAT, col2 FLOAT NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_FLOAT_NCI values(0.0, NULL, 0.0); +mysql> alter table test.t_FLOAT_NCI set tiflash replica 1 + +# DOUBLE +## clustered_index +mysql> drop table if exists test.t_DOUBLE_CI +mysql> create table test.t_DOUBLE_CI(pk DOUBLE NOT NULL, col1 DOUBLE, col2 DOUBLE NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_DOUBLE_CI values(0.0, NULL, 0.0); +mysql> alter table test.t_DOUBLE_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_DOUBLE_NCI +mysql> create table test.t_DOUBLE_NCI(pk DOUBLE NOT NULL, col1 DOUBLE, col2 DOUBLE NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_DOUBLE_NCI values(0.0, NULL, 0.0); +mysql> alter table test.t_DOUBLE_NCI set tiflash replica 1 + +# DECIMAL32 +## clustered_index +mysql> drop table if exists test.t_DECIMAL32_CI +mysql> create table test.t_DECIMAL32_CI(pk decimal(9, 1) NOT NULL, col1 decimal(9, 1), col2 decimal(9, 1) NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_DECIMAL32_CI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL32_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_DECIMAL32_NCI +mysql> create table test.t_DECIMAL32_NCI(pk decimal(9, 1) NOT NULL, col1 decimal(9, 1), col2 decimal(9, 1) NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_DECIMAL32_NCI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL32_NCI set tiflash replica 1 + +# DECIMAL64 +## clustered_index +mysql> drop table if exists test.t_DECIMAL64_CI +mysql> create table test.t_DECIMAL64_CI(pk decimal(18, 1) NOT NULL, col1 decimal(18, 1), col2 decimal(18, 1) NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_DECIMAL64_CI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL64_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_DECIMAL64_NCI +mysql> create table test.t_DECIMAL64_NCI(pk decimal(18, 1) NOT NULL, col1 decimal(18, 1), col2 decimal(18, 1) NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_DECIMAL64_NCI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL64_NCI set tiflash replica 1 + +# DECIMAL128 +## clustered_index +mysql> drop table if exists test.t_DECIMAL128_CI +mysql> create table test.t_DECIMAL128_CI(pk decimal(38, 1) NOT NULL, col1 decimal(38, 1), col2 decimal(38, 1) NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_DECIMAL128_CI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL128_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_DECIMAL128_NCI +mysql> create table test.t_DECIMAL128_NCI(pk decimal(38, 1) NOT NULL, col1 decimal(38, 1), col2 decimal(38, 1) NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_DECIMAL128_NCI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL128_NCI set tiflash replica 1 + +# DECIMAL256 +## clustered_index +mysql> drop table if exists test.t_DECIMAL256_CI +mysql> create table test.t_DECIMAL256_CI(pk decimal(65, 1) NOT NULL, col1 decimal(65, 1), col2 decimal(65, 1) NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_DECIMAL256_CI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL256_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_DECIMAL256_NCI +mysql> create table test.t_DECIMAL256_NCI(pk decimal(65, 1) NOT NULL, col1 decimal(65, 1), col2 decimal(65, 1) NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_DECIMAL256_NCI values(0.1, NULL, 0.1); +mysql> alter table test.t_DECIMAL256_NCI set tiflash replica 1 + +# CHAR +## clustered_index +mysql> drop table if exists test.t_CHAR_CI +mysql> create table test.t_CHAR_CI(pk CHAR NOT NULL, col1 CHAR, col2 CHAR NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_CHAR_CI values('a', NULL, 'b'); +mysql> alter table test.t_CHAR_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_CHAR_NCI +mysql> create table test.t_CHAR_NCI(pk CHAR NOT NULL, col1 CHAR, col2 CHAR NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_CHAR_NCI values('a', NULL, 'b'); +mysql> alter table test.t_CHAR_NCI set tiflash replica 1 + +# VARCHAR +## clustered_index +mysql> drop table if exists test.t_VARCHAR_CI +mysql> create table test.t_VARCHAR_CI(pk VARCHAR(30) NOT NULL, col1 VARCHAR(30), col2 VARCHAR(30) NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_VARCHAR_CI values('a', NULL, 'b'); +mysql> alter table test.t_VARCHAR_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_VARCHAR_NCI +mysql> create table test.t_VARCHAR_NCI(pk VARCHAR(30) NOT NULL, col1 VARCHAR(30), col2 VARCHAR(30) NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_VARCHAR_NCI values('a', NULL, 'b'); +mysql> alter table test.t_VARCHAR_NCI set tiflash replica 1 + +# BINARY +## clustered_index +mysql> drop table if exists test.t_BINARY_CI +mysql> create table test.t_BINARY_CI(pk BINARY NOT NULL, col1 BINARY, col2 BINARY NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_BINARY_CI values('1', NULL, '2'); +mysql> alter table test.t_BINARY_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_BINARY_NCI +mysql> create table test.t_BINARY_NCI(pk BINARY NOT NULL, col1 BINARY, col2 BINARY NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_BINARY_NCI values('1', NULL, '2'); +mysql> alter table test.t_BINARY_NCI set tiflash replica 1 + +# VARBINARY +## clustered_index +mysql> drop table if exists test.t_VARBINARY_CI +mysql> create table test.t_VARBINARY_CI(pk VARBINARY(30) NOT NULL, col1 VARBINARY(30), col2 VARBINARY(30) NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_VARBINARY_CI values('1234', NULL, '5678'); +mysql> alter table test.t_VARBINARY_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_VARBINARY_NCI +mysql> create table test.t_VARBINARY_NCI(pk VARBINARY(30) NOT NULL, col1 VARBINARY(30), col2 VARBINARY(30) NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_VARBINARY_NCI values('1234', NULL, '5678'); +mysql> alter table test.t_VARBINARY_NCI set tiflash replica 1 + +# BLOB +mysql> drop table if exists test.t_BLOB +mysql> create table test.t_BLOB(col1 BLOB, col2 BLOB NOT NULL); +mysql> insert into test.t_BLOB values(NULL, '1234'); +mysql> alter table test.t_BLOB set tiflash replica 1 + +# TEXT +mysql> drop table if exists test.t_TEXT +mysql> create table test.t_TEXT(col1 TEXT, col2 TEXT NOT NULL); +mysql> insert into test.t_TEXT values(NULL, 'b'); +mysql> alter table test.t_TEXT set tiflash replica 1 + +# ENUM +## clustered_index +mysql> drop table if exists test.t_ENUM_CI +mysql> create table test.t_ENUM_CI(pk enum('a','b') NOT NULL, col1 enum('a','b'), col2 enum('a','b') NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_ENUM_CI values('a', NULL, 'b'); +mysql> alter table test.t_ENUM_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_ENUM_NCI +mysql> create table test.t_ENUM_NCI(pk enum('a','b') NOT NULL, col1 enum('a','b'), col2 enum('a','b') NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_ENUM_NCI values('a', NULL, 'b'); +mysql> alter table test.t_ENUM_NCI set tiflash replica 1 + +# SET +## clustered_index +mysql> drop table if exists test.t_SET_CI +mysql> create table test.t_SET_CI(pk set('a','b') NOT NULL, col1 set('a','b'), col2 set('a','b') NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_SET_CI values('a', NULL, 'b'); +mysql> alter table test.t_SET_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_SET_NCI +mysql> create table test.t_SET_NCI(pk set('a','b') NOT NULL, col1 set('a','b'), col2 set('a','b') NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_SET_NCI values('a', NULL, 'b'); +mysql> alter table test.t_SET_NCI set tiflash replica 1 + +# DATE +## clustered_index +mysql> drop table if exists test.t_DATE_CI +mysql> create table test.t_DATE_CI(pk DATE NOT NULL, col1 DATE, col2 DATE NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_DATE_CI values('2010-01-01', NULL, '2010-01-02'); +mysql> alter table test.t_DATE_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_DATE_NCI +mysql> create table test.t_DATE_NCI(pk DATE NOT NULL, col1 DATE, col2 DATE NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_DATE_NCI values('2010-01-01', NULL, '2010-01-02'); +mysql> alter table test.t_DATE_NCI set tiflash replica 1 + +# TIME +## clustered_index +mysql> drop table if exists test.t_TIME_CI +mysql> create table test.t_TIME_CI(pk TIME NOT NULL, col1 TIME, col2 TIME NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_TIME_CI values('10:00:00', NULL, '11:00:00'); +mysql> alter table test.t_TIME_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_TIME_NCI +mysql> create table test.t_TIME_NCI(pk TIME NOT NULL, col1 TIME, col2 TIME NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_TIME_NCI values('10:00:00', NULL, '11:00:00'); +mysql> alter table test.t_TIME_NCI set tiflash replica 1 + +# DATETIME +## clustered_index +mysql> drop table if exists test.t_DATETIME_CI +mysql> create table test.t_DATETIME_CI(pk DATETIME NOT NULL, col1 DATETIME, col2 DATETIME NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_DATETIME_CI values('2010-01-01 11:00:00', NULL, '2011-01-01 12:00:00'); +mysql> alter table test.t_DATETIME_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_DATETIME_NCI +mysql> create table test.t_DATETIME_NCI(pk DATETIME NOT NULL, col1 DATETIME, col2 DATETIME NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_DATETIME_NCI values('2010-01-01 11:00:00', NULL, '2011-01-01 12:00:00'); +mysql> alter table test.t_DATETIME_NCI set tiflash replica 1 + +# TIMESTAMP +## clustered_index +mysql> drop table if exists test.t_TIMESTAMP_CI +mysql> create table test.t_TIMESTAMP_CI(pk TIMESTAMP NOT NULL, col1 TIMESTAMP, col2 TIMESTAMP NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_TIMESTAMP_CI values('2010-01-01 11:00:00', NULL, '2011-01-01 12:00:00'); +mysql> alter table test.t_TIMESTAMP_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_TIMESTAMP_NCI +mysql> create table test.t_TIMESTAMP_NCI(pk TIMESTAMP NOT NULL, col1 TIMESTAMP, col2 TIMESTAMP NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_TIMESTAMP_NCI values('2010-01-01 11:00:00', NULL, '2011-01-01 12:00:00'); +mysql> alter table test.t_TIMESTAMP_NCI set tiflash replica 1 + +# YEAR +## clustered_index +mysql> drop table if exists test.t_YEAR_CI +mysql> create table test.t_YEAR_CI(pk YEAR NOT NULL, col1 YEAR, col2 YEAR NOT NULL, PRIMARY KEY CLUSTERED (pk)); +mysql> insert into test.t_YEAR_CI values('2021', NULL, '2022'); +mysql> alter table test.t_YEAR_CI set tiflash replica 1 +## nonclustered_index +mysql> drop table if exists test.t_YEAR_NCI +mysql> create table test.t_YEAR_NCI(pk YEAR NOT NULL, col1 YEAR, col2 YEAR NOT NULL, PRIMARY KEY NONCLUSTERED (pk)); +mysql> insert into test.t_YEAR_NCI values('2021', NULL, '2022'); +mysql> alter table test.t_YEAR_NCI set tiflash replica 1 + +# JSON +mysql> drop table if exists test.t_JSON; +mysql> create table test.t_JSON(col1 JSON, col2 JSON NOT NULL); +mysql> insert into test.t_JSON values(NULL, '[1, 2, 3]'); +mysql> alter table test.t_JSON set tiflash replica 1 + + +# wait table +func> wait_table test t_TINYINT_CI +func> wait_table test t_TINYINT_NCI +func> wait_table test t_SMALLINT_CI +func> wait_table test t_SMALLINT_NCI +func> wait_table test t_MEDIUMINT_CI +func> wait_table test t_MEDIUMINT_NCI +func> wait_table test t_INT_CI +func> wait_table test t_INT_NCI +func> wait_table test t_BIGINT_CI +func> wait_table test t_BIGINT_NCI +func> wait_table test t_FLOAT_CI +func> wait_table test t_FLOAT_NCI +func> wait_table test t_DOUBLE_CI +func> wait_table test t_DOUBLE_NCI +func> wait_table test t_DECIMAL32_CI +func> wait_table test t_DECIMAL32_NCI +func> wait_table test t_DECIMAL64_CI +func> wait_table test t_DECIMAL64_NCI +func> wait_table test t_DECIMAL128_CI +func> wait_table test t_DECIMAL128_NCI +func> wait_table test t_DECIMAL256_CI +func> wait_table test t_DECIMAL256_NCI +func> wait_table test t_CHAR_CI +func> wait_table test t_CHAR_NCI +func> wait_table test t_VARCHAR_CI +func> wait_table test t_VARCHAR_NCI +func> wait_table test t_BINARY_CI +func> wait_table test t_BINARY_NCI +func> wait_table test t_VARBINARY_CI +func> wait_table test t_VARBINARY_NCI +func> wait_table test t_BLOB +func> wait_table test t_TEXT +func> wait_table test t_ENUM_CI +func> wait_table test t_ENUM_NCI +func> wait_table test t_SET_CI +func> wait_table test t_SET_NCI +func> wait_table test t_DATE_CI +func> wait_table test t_DATE_NCI +func> wait_table test t_TIME_CI +func> wait_table test t_TIME_NCI +func> wait_table test t_DATETIME_CI +func> wait_table test t_DATETIME_NCI +func> wait_table test t_TIMESTAMP_CI +func> wait_table test t_TIMESTAMP_NCI +func> wait_table test t_YEAR_CI +func> wait_table test t_YEAR_NCI +func> wait_table test t_JSON + + +# TINYINT +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_TINYINT_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_TINYINT_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ + +# SMALLINT +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_SMALLINT_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_SMALLINT_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ + +# MEDIUMINT +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_MEDIUMINT_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_MEDIUMINT_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ + +# INT +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_INT_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_INT_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ + +# BIGINT +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_BIGINT_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_BIGINT_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ + +# FLOAT +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_FLOAT_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_FLOAT_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ + +# DOUBLE +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DOUBLE_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DOUBLE_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 0 | NULL | 0 | ++----+------+------+ + +# DECIMAL32 +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL32_CI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL32_NCI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ + +# DECIMAL64 +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL64_CI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL64_NCI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ + +# DECIMAL128 +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL128_CI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL128_NCI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ + +# DECIMAL256 +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL256_CI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DECIMAL256_NCI; ++-----+------+------+ +| pk | col1 | col2 | ++-----+------+------+ +| 0.1 | NULL | 0.1 | ++-----+------+------+ + +# CHAR +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_CHAR_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_CHAR_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ + +# VARCHAR +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_VARCHAR_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_VARCHAR_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ + +# BINARY +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_BINARY_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 1 | NULL | 2 | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_BINARY_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| 1 | NULL | 2 | ++----+------+------+ + +# VARBINARY +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_VARBINARY_CI; ++------+------+------+ +| pk | col1 | col2 | ++------+------+------+ +| 1234 | NULL | 5678 | ++------+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_VARBINARY_NCI; ++------+------+------+ +| pk | col1 | col2 | ++------+------+------+ +| 1234 | NULL | 5678 | ++------+------+------+ + +# BLOB +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_BLOB; ++------+------+ +| col1 | col2 | ++------+------+ +| NULL | 1234 | ++------+------+ + +# TEXT +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_TEXT; ++------+------+ +| col1 | col2 | ++------+------+ +| NULL | b | ++------+------+ + +# ENUM +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_ENUM_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_ENUM_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ + +# SET +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_SET_CI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_SET_NCI; ++----+------+------+ +| pk | col1 | col2 | ++----+------+------+ +| a | NULL | b | ++----+------+------+ + +# DATE +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DATE_CI; ++------------+------+------------+ +| pk | col1 | col2 | ++------------+------+------------+ +| 2010-01-01 | NULL | 2010-01-02 | ++------------+------+------------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DATE_NCI; ++------------+------+------------+ +| pk | col1 | col2 | ++------------+------+------------+ +| 2010-01-01 | NULL | 2010-01-02 | ++------------+------+------------+ + +# TIME +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_TIME_CI; ++----------+------+----------+ +| pk | col1 | col2 | ++----------+------+----------+ +| 10:00:00 | NULL | 11:00:00 | ++----------+------+----------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_TIME_NCI; ++----------+------+----------+ +| pk | col1 | col2 | ++----------+------+----------+ +| 10:00:00 | NULL | 11:00:00 | ++----------+------+----------+ + +# DATETIME +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DATETIME_CI; ++---------------------+------+---------------------+ +| pk | col1 | col2 | ++---------------------+------+---------------------+ +| 2010-01-01 11:00:00 | NULL | 2011-01-01 12:00:00 | ++---------------------+------+---------------------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_DATETIME_NCI; ++---------------------+------+---------------------+ +| pk | col1 | col2 | ++---------------------+------+---------------------+ +| 2010-01-01 11:00:00 | NULL | 2011-01-01 12:00:00 | ++---------------------+------+---------------------+ + +# TIMESTAMP +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_TIMESTAMP_CI; ++---------------------+------+---------------------+ +| pk | col1 | col2 | ++---------------------+------+---------------------+ +| 2010-01-01 11:00:00 | NULL | 2011-01-01 12:00:00 | ++---------------------+------+---------------------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_TIMESTAMP_NCI; ++---------------------+------+---------------------+ +| pk | col1 | col2 | ++---------------------+------+---------------------+ +| 2010-01-01 11:00:00 | NULL | 2011-01-01 12:00:00 | ++---------------------+------+---------------------+ + +# YEAR +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_YEAR_CI; ++------+------+------+ +| pk | col1 | col2 | ++------+------+------+ +| 2021 | NULL | 2022 | ++------+------+------+ +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_YEAR_NCI; ++------+------+------+ +| pk | col1 | col2 | ++------+------+------+ +| 2021 | NULL | 2022 | ++------+------+------+ + +# JSON +mysql> set session tidb_isolation_read_engines='tiflash'; select * from test.t_JSON; ++------+-----------+ +| col1 | col2 | ++------+-----------+ +| NULL | [1, 2, 3] | ++------+-----------+ + + +# drop table +mysql> drop table if exists test.t_TINYINT_CI +mysql> drop table if exists test.t_TINYINT_NCI +mysql> drop table if exists test.t_SMALLINT_CI +mysql> drop table if exists test.t_SMALLINT_NCI +mysql> drop table if exists test.t_MEDIUMINT_CI +mysql> drop table if exists test.t_MEDIUMINT_NCI +mysql> drop table if exists test.t_INT_CI +mysql> drop table if exists test.t_INT_NCI +mysql> drop table if exists test.t_BIGINT_CI +mysql> drop table if exists test.t_BIGINT_NCI +mysql> drop table if exists test.t_FLOAT_CI +mysql> drop table if exists test.t_FLOAT_NCI +mysql> drop table if exists test.t_DOUBLE_CI +mysql> drop table if exists test.t_DOUBLE_NCI +mysql> drop table if exists test.t_DECIMAL32_CI +mysql> drop table if exists test.t_DECIMAL32_NCI +mysql> drop table if exists test.t_DECIMAL64_CI +mysql> drop table if exists test.t_DECIMAL64_NCI +mysql> drop table if exists test.t_DECIMAL128_CI +mysql> drop table if exists test.t_DECIMAL128_NCI +mysql> drop table if exists test.t_DECIMAL256_CI +mysql> drop table if exists test.t_DECIMAL256_NCI +mysql> drop table if exists test.t_CHAR_CI +mysql> drop table if exists test.t_CHAR_NCI +mysql> drop table if exists test.t_VARCHAR_CI +mysql> drop table if exists test.t_VARCHAR_NCI +mysql> drop table if exists test.t_BINARY_CI +mysql> drop table if exists test.t_BINARY_NCI +mysql> drop table if exists test.t_VARBINARY_CI +mysql> drop table if exists test.t_VARBINARY_NCI +mysql> drop table if exists test.t_BLOB +mysql> drop table if exists test.t_TEXT +mysql> drop table if exists test.t_ENUM_CI +mysql> drop table if exists test.t_ENUM_NCI +mysql> drop table if exists test.t_SET_CI +mysql> drop table if exists test.t_SET_NCI +mysql> drop table if exists test.t_DATE_CI +mysql> drop table if exists test.t_DATE_NCI +mysql> drop table if exists test.t_TIME_CI +mysql> drop table if exists test.t_TIME_NCI +mysql> drop table if exists test.t_DATETIME_CI +mysql> drop table if exists test.t_DATETIME_NCI +mysql> drop table if exists test.t_TIMESTAMP_CI +mysql> drop table if exists test.t_TIMESTAMP_NCI +mysql> drop table if exists test.t_YEAR_CI +mysql> drop table if exists test.t_YEAR_NCI +mysql> drop table if exists test.t_JSON