From 3c6973d5a81347a4fd3ae2a32167f69edd7ea8c5 Mon Sep 17 00:00:00 2001 From: lei yu Date: Tue, 29 Oct 2019 17:55:10 +0800 Subject: [PATCH] [FLASH-453]Support default value of CAST expression (#286) * refactor default_value * Apply suggestions from code review * enable alter default value test * add default_value to make sure read can fill value with it * fix issue with reading Float default value * add test for read Float default value * resolve suggestions * add abs * fix issue with DateTime default value * add test for DateTime default value * modify test case * handle Decimal64 * modify expect values * format * fix issue with Decimal default_value * modify test case * resolve suggestions * fix bug: column in StorageDeltaMerge but not in TiDB::TableInfo::columns --- dbms/src/Core/ColumnWithTypeAndName.h | 5 +- dbms/src/Storages/DeltaMerge/Chunk.cpp | 139 +++++++++++++-- .../Storages/DeltaMerge/DeltaMergeDefines.h | 2 +- .../Storages/DeltaMerge/DeltaMergeHelpers.h | 6 +- .../Storages/DeltaMerge/DeltaMergeStore.cpp | 10 +- .../DeltaMerge/tests/gtest_dm_chunk.cpp | 2 +- .../tests/gtest_dm_delta_merge_store.cpp | 168 ++++++++++++++++++ .../DeltaMerge/tests/gtest_dm_segment.cpp | 2 +- dbms/src/Storages/StorageDeltaMerge.cpp | 23 ++- .../ddl/alter_default_value.test | 25 +-- .../raft/schema/rename_column.test | 2 - 11 files changed, 334 insertions(+), 50 deletions(-) diff --git a/dbms/src/Core/ColumnWithTypeAndName.h b/dbms/src/Core/ColumnWithTypeAndName.h index 8bc059ddf43..69f1a259143 100644 --- a/dbms/src/Core/ColumnWithTypeAndName.h +++ b/dbms/src/Core/ColumnWithTypeAndName.h @@ -25,10 +25,11 @@ struct ColumnWithTypeAndName /// TODO Handle column_id properly after we support DDL. Int64 column_id; + Field default_value; ColumnWithTypeAndName(): ColumnWithTypeAndName(nullptr, nullptr, "") {} - ColumnWithTypeAndName(ColumnPtr column_, const DataTypePtr & type_, const String & name_, Int64 column_id_ = 0) - : column(std::move(column_)), type(type_), name(name_), column_id(column_id_) {} + ColumnWithTypeAndName(ColumnPtr column_, const DataTypePtr & type_, const String & name_, Int64 column_id_ = 0, const Field & default_value_ = Field()) + : column(std::move(column_)), type(type_), name(name_), column_id(column_id_), default_value(default_value_) {} /// Uses type->createColumn() to create column ColumnWithTypeAndName(const DataTypePtr & type_, const String & name_) diff --git a/dbms/src/Storages/DeltaMerge/Chunk.cpp b/dbms/src/Storages/DeltaMerge/Chunk.cpp index 0dcb5a7a08b..df962eca9a7 100644 --- a/dbms/src/Storages/DeltaMerge/Chunk.cpp +++ b/dbms/src/Storages/DeltaMerge/Chunk.cpp @@ -1,9 +1,12 @@ +#include + #include #include #include #include #include +#include namespace DB { @@ -238,20 +241,120 @@ void readChunkData(MutableColumns & columns, // New column after ddl is not exist in chunk's meta, fill with default value IColumn & col = *columns[index]; - if (define.default_value.empty()) + // Read default value from `define.default_value` + ColumnPtr tmp_col; + if (define.default_value.isNull()) + { + tmp_col = define.type->createColumnConstWithDefaultValue(rows_limit); + } + // TODO: `define.default_value` may be not matched with `define.type` + // For example: ... ADD COLUMN f32 Float32 '1.23' + // After parsing and interpreting, we will get a `type` Float32, + // while `default_value` will be inferred as String. + // So we should do some process before reading value or during applying alter to guarantee the correctness. + else if (define.type->equals(*DataTypeFactory::instance().get("Float32")) + || define.type->equals(*DataTypeFactory::instance().get("Float64"))) { - ColumnPtr tmp_col = define.type->createColumnConstWithDefaultValue(rows_limit)->convertToFullColumnIfConst(); - col.insertRangeFrom(*tmp_col, 0, rows_limit); + Float64 real; + auto dec32 = DecimalField(Decimal32(), 0); + auto dec64 = DecimalField(Decimal64(), 0); + auto dec128 = DecimalField(Decimal128(), 0); + auto dec256 = DecimalField(Decimal256(), 0); + if (define.default_value.tryGet(dec32)) + { + real = static_cast(dec32); + } + else if (define.default_value.tryGet(dec64)) + { + real = static_cast(dec64); + } + else if (define.default_value.tryGet(dec128)) + { + real = static_cast(dec128); + } + else if (define.default_value.tryGet(dec256)) + { + real = static_cast(dec256); + } + else + { + throw Exception("Unsupported literal for default value", ErrorCodes::NOT_IMPLEMENTED); + } + tmp_col = define.type->createColumnConst(rows_limit, Field(real)); + } + else if (define.type->equals(*DataTypeFactory::instance().get("DateTime"))) + { + auto date = safeGet(define.default_value); + time_t time; + ReadBufferFromMemory buf(date.data(), date.size()); + readDateTimeText(time, buf); + tmp_col = define.type->createColumnConst(rows_limit, Field(UInt64(time))); + } + else if (std::strcmp(define.type->getFamilyName(), "Decimal") == 0) + { + Int64 value; + Int128 value128; + Int256 value256; + UInt32 scale; + { + auto dec32 = DecimalField(Decimal32(), 0); + auto dec64 = DecimalField(Decimal64(), 0); + auto dec128 = DecimalField(Decimal128(), 0); + auto dec256 = DecimalField(Decimal256(), 0); + if (define.default_value.tryGet(dec32)) + { + value = dec32.getValue().value; + scale = dec32.getScale(); + } + else if (define.default_value.tryGet(dec64)) + { + value = dec64.getValue().value; + scale = dec64.getScale(); + } + else if (define.default_value.tryGet(dec128)) + { + value128 = dec128.getValue().value; + scale = dec128.getScale(); + } + else if (define.default_value.tryGet(dec256)) + { + value256 = dec256.getValue().value; + scale = dec256.getScale(); + } + } + + if (define.type->getTypeId() == TypeIndex::Decimal32) + { + auto dec = DecimalField(value, scale); + tmp_col = define.type->createColumnConst(rows_limit, toField(dec)); + } + else if (define.type->getTypeId() == TypeIndex::Decimal64) + { + auto dec = DecimalField(value, scale); + tmp_col = define.type->createColumnConst(rows_limit, toField(dec)); + } + else if (define.type->getTypeId() == TypeIndex::Decimal128) + { + auto dec = DecimalField(value128, scale); + tmp_col = define.type->createColumnConst(rows_limit, toField(dec)); + } + else if (define.type->getTypeId() == TypeIndex::Decimal256) + { + auto dec = DecimalField(value256, scale); + tmp_col = define.type->createColumnConst(rows_limit, toField(dec)); + } + else + { + throw Exception("Unsupported literal for default value", ErrorCodes::NOT_IMPLEMENTED); + } } else { - // Read default value from `define.default_value` - MutableColumnPtr tmp_col = define.type->createColumn(); - ReadBufferFromMemory buff(define.default_value.c_str(), define.default_value.size()); - define.type->deserializeTextEscaped(*tmp_col, buff); - ColumnPtr tmp_full_col = tmp_col->replicate(IColumn::Offsets(1, rows_limit)); - col.insertRangeFrom(*tmp_full_col, 0, rows_limit); + tmp_col = define.type->createColumnConst(rows_limit, define.default_value); } + tmp_col = tmp_col->convertToFullColumnIfConst(); + + col.insertRangeFrom(*tmp_col, 0, rows_limit); } } @@ -643,11 +746,21 @@ void insertRangeFromWithNumericTypeCast(const ColumnPtr & from_col, // /// We are applying cast from nullable to not null, scan to fill "NULL" with default value TypeTo default_value = 0; // if read_define.default_value is empty, fill with 0 - if (!read_define.default_value.empty()) + if (read_define.default_value.isNull()) + { + // Do nothing + } + else if (read_define.default_value.getType() == Field::Types::Int64) + { + default_value = read_define.default_value.safeGet(); + } + else if (read_define.default_value.getType() == Field::Types::UInt64) + { + default_value = read_define.default_value.safeGet(); + } + else { - // parse from text - ReadBufferFromMemory buff(read_define.default_value.c_str(), read_define.default_value.size()); - readIntTextUnsafe(default_value, buff); + throw Exception("Invalid column value type", ErrorCodes::BAD_ARGUMENTS); } const size_t to_offset_before_inserted = to_array_ptr->size() - rows_limit; diff --git a/dbms/src/Storages/DeltaMerge/DeltaMergeDefines.h b/dbms/src/Storages/DeltaMerge/DeltaMergeDefines.h index a113b560efb..75424f5c970 100644 --- a/dbms/src/Storages/DeltaMerge/DeltaMergeDefines.h +++ b/dbms/src/Storages/DeltaMerge/DeltaMergeDefines.h @@ -72,7 +72,7 @@ struct ColumnDefine ColId id; String name; DataTypePtr type; - String default_value; + Field default_value; explicit ColumnDefine(ColId id_ = 0, String name_ = "", DataTypePtr type_ = nullptr) : id(id_), name(std::move(name_)), type(std::move(type_)) diff --git a/dbms/src/Storages/DeltaMerge/DeltaMergeHelpers.h b/dbms/src/Storages/DeltaMerge/DeltaMergeHelpers.h index 7cfc0dad5a6..5371f6209f2 100644 --- a/dbms/src/Storages/DeltaMerge/DeltaMergeHelpers.h +++ b/dbms/src/Storages/DeltaMerge/DeltaMergeHelpers.h @@ -123,9 +123,9 @@ inline PaddedPODArray const * getColumnVectorDataPtr(const Block & block, siz return toColumnVectorDataPtr(block.getByPosition(pos).column); } -inline void addColumnToBlock(Block & block, ColId col_id, const String & col_name, const DataTypePtr & col_type, const ColumnPtr & col) +inline void addColumnToBlock(Block & block, ColId col_id, const String & col_name, const DataTypePtr & col_type, const ColumnPtr & col, const Field & default_value = Field()) { - ColumnWithTypeAndName column(col, col_type, col_name, col_id); + ColumnWithTypeAndName column(col, col_type, col_name, col_id, default_value); block.insert(std::move(column)); } @@ -133,7 +133,7 @@ inline Block toEmptyBlock(const ColumnDefines & columns) { Block block; for (auto & c : columns) - addColumnToBlock(block, c.id, c.name, c.type, c.type->createColumn()); + addColumnToBlock(block, c.id, c.name, c.type, c.type->createColumn(), c.default_value); return block; } diff --git a/dbms/src/Storages/DeltaMerge/DeltaMergeStore.cpp b/dbms/src/Storages/DeltaMerge/DeltaMergeStore.cpp index c2902213e57..199e317ed2f 100644 --- a/dbms/src/Storages/DeltaMerge/DeltaMergeStore.cpp +++ b/dbms/src/Storages/DeltaMerge/DeltaMergeStore.cpp @@ -820,8 +820,7 @@ inline void setColumnDefineDefaultValue(const AlterCommand & command, ColumnDefi if (auto default_literal = typeid_cast(command.default_expression.get()); default_literal && default_literal->value.getType() == Field::Types::String) { - const auto default_val = safeGet(default_literal->value); - define.default_value = default_val; + define.default_value = default_literal->value; } else if (auto default_cast_expr = typeid_cast(command.default_expression.get()); default_cast_expr && default_cast_expr->name == "CAST" /* ParserCastExpression::name */) @@ -833,14 +832,13 @@ inline void setColumnDefineDefaultValue(const AlterCommand & command, ColumnDefi } auto default_literal_in_cast = typeid_cast(default_cast_expr->arguments->children[0].get()); - if (default_literal_in_cast && default_literal_in_cast->value.getType() == Field::Types::String) + if (default_literal_in_cast) { - const auto default_value = safeGet(default_literal_in_cast->value); - define.default_value = default_value; + define.default_value = default_literal_in_cast->value; } else { - throw Exception("First argument in CAST expression must be a string", ErrorCodes::NOT_IMPLEMENTED); + throw Exception("Invalid CAST expression", ErrorCodes::BAD_ARGUMENTS); } } else diff --git a/dbms/src/Storages/DeltaMerge/tests/gtest_dm_chunk.cpp b/dbms/src/Storages/DeltaMerge/tests/gtest_dm_chunk.cpp index 437ce95b5b7..f3e65a96921 100644 --- a/dbms/src/Storages/DeltaMerge/tests/gtest_dm_chunk.cpp +++ b/dbms/src/Storages/DeltaMerge/tests/gtest_dm_chunk.cpp @@ -295,7 +295,7 @@ TEST(ChunkColumnCast_test, DISABLED_CastNullableToNotNullWithNonZeroDefaultValue { DataTypePtr read_data_type = typeFromString(to_type); ColumnDefine read_define(0, "c", read_data_type); - read_define.default_value = "5"; + read_define.default_value = Field(String("5")); MutableColumnPtr memory_column = read_data_type->createColumn(); memory_column->reserve(3); diff --git a/dbms/src/Storages/DeltaMerge/tests/gtest_dm_delta_merge_store.cpp b/dbms/src/Storages/DeltaMerge/tests/gtest_dm_delta_merge_store.cpp index f0cb2d57277..646015fc42b 100644 --- a/dbms/src/Storages/DeltaMerge/tests/gtest_dm_delta_merge_store.cpp +++ b/dbms/src/Storages/DeltaMerge/tests/gtest_dm_delta_merge_store.cpp @@ -1,4 +1,5 @@ #include +#include #include "dm_basic_include.h" #include @@ -6,6 +7,8 @@ #include #include +#include +#include #include #include @@ -1086,6 +1089,171 @@ catch (const Exception & e) throw; } +TEST_F(DeltaMergeStore_test, DDLAddColumnFloat32) +try +{ + const String col_name_to_add = "f32"; + const ColId col_id_to_add = 2; + const DataTypePtr col_type_to_add = DataTypeFactory::instance().get("Float32"); + + // write some rows before DDL + { + Block block = DMTestEnv::prepareSimpleWriteBlock(0, 1, false); + store->write(*context, context->getSettingsRef(), block); + } + + // DDL add column f32 with default value + { + AlterCommands commands; + { + AlterCommand com; + com.type = AlterCommand::ADD_COLUMN; + com.data_type = col_type_to_add; + com.column_name = col_name_to_add; + + // mock default value + // actual ddl is like: ADD COLUMN `f32` Float32 DEFAULT 1.23 + auto cast = std::make_shared(); + { + cast->name = "CAST"; + ASTPtr arg = std::make_shared(toField(DecimalField(Decimal32(123), 2))); + cast->arguments = std::make_shared(); + cast->children.push_back(cast->arguments); + cast->arguments->children.push_back(arg); + cast->arguments->children.push_back(ASTPtr()); // dummy alias + } + com.default_expression = cast; + commands.emplace_back(std::move(com)); + } + ColumnID _col_to_add = col_id_to_add; + store->applyAlters(commands, std::nullopt, _col_to_add, *context); + } + + // try read + { + auto in = store->read(*context, + context->getSettingsRef(), + store->getTableColumns(), + {HandleRange::newAll()}, + /* num_streams= */ 1, + /* max_version= */ std::numeric_limits::max(), + /* expected_block_size= */ 1024)[0]; + + in->readPrefix(); + while (Block block = in->read()) + { + for (auto & itr : block) + { + auto c = itr.column; + for (size_t i = 0; i < c->size(); i++) + { + if (itr.name == "f32") + { + Field tmp; + c->get(i, tmp); + // There is some loss of precision during the convertion, so we just do a rough comparison + Float64 epsilon = 0.00001; + EXPECT_TRUE(std::abs(tmp.get() - 1.23) < epsilon); + } + } + } + } + in->readSuffix(); + } +} +catch (const Exception & e) +{ + std::string text = e.displayText(); + + auto embedded_stack_trace_pos = text.find("Stack trace"); + std::cerr << "Code: " << e.code() << ". " << text << std::endl << std::endl; + if (std::string::npos == embedded_stack_trace_pos) + std::cerr << "Stack trace:" << std::endl << e.getStackTrace().toString() << std::endl; + + throw; +} + +TEST_F(DeltaMergeStore_test, DDLAddColumnDateTime) +try +{ + const String col_name_to_add = "dt"; + const ColId col_id_to_add = 2; + const DataTypePtr col_type_to_add = DataTypeFactory::instance().get("DateTime"); + + // write some rows before DDL + { + Block block = DMTestEnv::prepareSimpleWriteBlock(0, 1, false); + store->write(*context, context->getSettingsRef(), block); + } + + // DDL add column date with default value + { + AlterCommands commands; + { + AlterCommand com; + com.type = AlterCommand::ADD_COLUMN; + com.data_type = col_type_to_add; + com.column_name = col_name_to_add; + + // mock default value + // actual ddl is like: ADD COLUMN `date` DateTime DEFAULT '1999-09-09 12:34:56' + auto cast = std::make_shared(); + { + cast->name = "CAST"; + ASTPtr arg = std::make_shared(toField(String("1999-09-09 12:34:56"))); + cast->arguments = std::make_shared(); + cast->children.push_back(cast->arguments); + cast->arguments->children.push_back(arg); + cast->arguments->children.push_back(ASTPtr()); // dummy alias + } + com.default_expression = cast; + commands.emplace_back(std::move(com)); + } + ColumnID _col_to_add = col_id_to_add; + store->applyAlters(commands, std::nullopt, _col_to_add, *context); + } + + // try read + { + auto in = store->read(*context, + context->getSettingsRef(), + store->getTableColumns(), + {HandleRange::newAll()}, + /* num_streams= */ 1, + /* max_version= */ std::numeric_limits::max(), + /* expected_block_size= */ 1024)[0]; + + in->readPrefix(); + while (Block block = in->read()) + { + for (auto & itr : block) + { + auto c = itr.column; + for (size_t i = 0; i < c->size(); i++) + { + if (itr.name == "dt") + { + // Timestamp for '1999-09-09 12:34:56' + EXPECT_EQ(c->getUInt(i), 936851696UL); + } + } + } + } + in->readSuffix(); + } +} +catch (const Exception & e) +{ + std::string text = e.displayText(); + + auto embedded_stack_trace_pos = text.find("Stack trace"); + std::cerr << "Code: " << e.code() << ". " << text << std::endl << std::endl; + if (std::string::npos == embedded_stack_trace_pos) + std::cerr << "Stack trace:" << std::endl << e.getStackTrace().toString() << std::endl; + + throw; +} + TEST_F(DeltaMergeStore_test, DDLRenameColumn) try { diff --git a/dbms/src/Storages/DeltaMerge/tests/gtest_dm_segment.cpp b/dbms/src/Storages/DeltaMerge/tests/gtest_dm_segment.cpp index ba327c9ef38..c54aecadbb7 100644 --- a/dbms/src/Storages/DeltaMerge/tests/gtest_dm_segment.cpp +++ b/dbms/src/Storages/DeltaMerge/tests/gtest_dm_segment.cpp @@ -1091,7 +1091,7 @@ TEST_F(Segment_test, DDLAddColumnWithDefaultValue) const ColumnID new_column_id = 4; ColumnDefine new_column_define(new_column_id, new_column_name, DataTypeFactory::instance().get("Int8")); const Int8 new_column_default_value_int = 16; - new_column_define.default_value = DB::toString(new_column_default_value_int); + new_column_define.default_value = toField(new_column_default_value_int); { ColumnDefines columns_before_ddl = DMTestEnv::getDefaultColumns(); diff --git a/dbms/src/Storages/StorageDeltaMerge.cpp b/dbms/src/Storages/StorageDeltaMerge.cpp index 28e3eabe0cd..04da9f2543f 100644 --- a/dbms/src/Storages/StorageDeltaMerge.cpp +++ b/dbms/src/Storages/StorageDeltaMerge.cpp @@ -77,8 +77,14 @@ StorageDeltaMerge::StorageDeltaMerge(const String & path_, ColumnDefine column_define(0, col.name, col.type); if (table_info_) { - /// If TableInfo from TiDB is not empty, we get column id from TiDB + /// If TableInfo from TiDB is not empty, we get column id and default value from TiDB + auto & columns = table_info_->get().columns; column_define.id = table_info_->get().getColumnID(column_define.name); + auto column + = std::find_if(columns.begin(), columns.end(), [&](const ColumnInfo & v) -> bool { return v.id == column_define.id; }); + + if (column != columns.end()) + column_define.default_value = column->defaultValueToField(); } else { @@ -86,6 +92,7 @@ StorageDeltaMerge::StorageDeltaMerge(const String & path_, column_define.id = max_column_id_used++; } + if (pks.count(col.name)) { if (!col.type->isValueRepresentedByInteger()) @@ -371,8 +378,7 @@ BlockInputStreams StorageDeltaMerge::read( // col_define.name = column.name; col_define.id = column.column_id; col_define.type = column.type; - // FIXME set non-empty default value so that we can fill missing value with the right default value - // col_define.default_value = ""; + col_define.default_value = column.default_value; } to_read.push_back(col_define); } @@ -417,16 +423,16 @@ BlockInputStreams StorageDeltaMerge::read( // { { std::stringstream ss; - for (const auto ®ion: mvcc_query_info.regions_query_info) + for (const auto & region : mvcc_query_info.regions_query_info) { - const auto &range = region.range_in_table; + const auto & range = region.range_in_table; ss << region.region_id << "[" << range.first.toString() << "," << range.second.toString() << "),"; } LOG_TRACE(log, "reading ranges: orig: " << ss.str()); } { std::stringstream ss; - for (const auto &range : ranges) + for (const auto & range : ranges) ss << range.toString() << ","; LOG_TRACE(log, "reading ranges: " << ss.str()); } @@ -624,9 +630,8 @@ void updateDeltaMergeTableCreateStatement( // { if (hidden_columns.has(column_define.name)) continue; - Field default_field; - TiDB::ColumnInfo column_info = reverseGetColumnInfo(NameAndTypePair{column_define.name, column_define.type}, column_define.id, default_field); - // TODO column_info.origin_default_value = column_define.default_value; + TiDB::ColumnInfo column_info = reverseGetColumnInfo( + NameAndTypePair{column_define.name, column_define.type}, column_define.id, column_define.default_value); table_info_from_store.columns.emplace_back(std::move(column_info)); } } diff --git a/tests/delta-merge-test/ddl/alter_default_value.test b/tests/delta-merge-test/ddl/alter_default_value.test index 46d87c37980..7996b8d861e 100644 --- a/tests/delta-merge-test/ddl/alter_default_value.test +++ b/tests/delta-merge-test/ddl/alter_default_value.test @@ -23,24 +23,25 @@ ## These alter command will throw exception now ## See FLASH-453 -#>> alter table dm_test add column i1 Int32 default 999 -#>> alter table dm_test add column f32_1 Float32 default 1.234 -#>> alter table dm_test add column f64_1 Float64 default 1.23456 -#>> alter table dm_test add column dec1 Decimal(10,4) default 3.1415 -#>> alter table dm_test add column fs1 FixedString(4) default 'aaa' -#>> alter table dm_test add column dt1 DateTime default '1999-09-09 12:34:56' +>> alter table dm_test add column i1 Int32 default 999 +>> alter table dm_test add column f32_1 Float32 default 1.234 +>> alter table dm_test add column f64_1 Float64 default 1.234 +>> alter table dm_test add column dec1 Decimal(10,4) default 3.1415 +>> alter table dm_test add column fs1 FixedString(4) default 'aaa' +>> alter table dm_test add column dt1 DateTime default '1999-09-09 12:34:56' >> select * from dm_test where pk = 1 -┌─pk─┬─i0─┬─f32_0─┬─f64_0─┬─dec0───┬─s0─┬─fs0──────┬─────────────────dt0─┐ -│ 1 │ 0 │ 0 │ 0 │ 0.0000 │ │ \0\0\0\0 │ 0000-00-00 00:00:00 │ -└────┴────┴───────┴───────┴────────┴────┴──────────┴─────────────────────┘ +┌─pk─┬─i0─┬─f32_0─┬─f64_0─┬─dec0───┬─s0─┬─fs0──────┬─────────────────dt0─┬──i1─┬─f32_1─┬─f64_1─┬─dec1───┬─fs1───┬─────────────────dt1─┐ +│ 1 │ 0 │ 0 │ 0 │ 0.0000 │ │ \0\0\0\0 │ 0000-00-00 00:00:00 │ 999 │ 1.234 │ 1.234 │ 3.1415 │ aaa\0 │ 1999-09-09 12:34:56 │ +└────┴────┴───────┴───────┴────────┴────┴──────────┴─────────────────────┴─────┴───────┴───────┴────────┴───────┴─────────────────────┘ + ## insert a row, missing fields will be filled with default value >> insert into table dm_test(pk) values(3) >> select * from dm_test where pk = 3 -┌─pk─┬─i0─┬─f32_0─┬─f64_0─┬─dec0───┬─s0─┬─fs0──────┬─────────────────dt0─┐ -│ 3 │ 0 │ 0 │ 0 │ 0.0000 │ │ \0\0\0\0 │ 0000-00-00 00:00:00 │ -└────┴────┴───────┴───────┴────────┴────┴──────────┴─────────────────────┘ +┌─pk─┬─i0─┬─f32_0─┬─f64_0─┬─dec0───┬─s0─┬─fs0──────┬─────────────────dt0─┬──i1─┬─f32_1─┬─f64_1─┬─dec1───┬─fs1───┬─────────────────dt1─┐ +│ 3 │ 0 │ 0 │ 0 │ 0.0000 │ │ \0\0\0\0 │ 0000-00-00 00:00:00 │ 999 │ 1.234 │ 1.234 │ 3.1415 │ aaa\0 │ 1999-09-09 12:34:56 │ +└────┴────┴───────┴───────┴────────┴────┴──────────┴─────────────────────┴─────┴───────┴───────┴────────┴───────┴─────────────────────┘ ## clean up >> drop table if exists dm_test diff --git a/tests/delta-merge-test/raft/schema/rename_column.test b/tests/delta-merge-test/raft/schema/rename_column.test index d330cb8212b..02dd364c938 100644 --- a/tests/delta-merge-test/raft/schema/rename_column.test +++ b/tests/delta-merge-test/raft/schema/rename_column.test @@ -154,8 +154,6 @@ │ test │ 2 │ 51 │ └───────┴───────┴─────────────┘ -#TODO we skip this test for now, since we don't support add column with default value -#RETURN # test drop and then rename and then create => DBGInvoke __drop_column_from_tidb_table(default, test, col_1)