diff --git a/dbms/src/Common/FieldVisitors.cpp b/dbms/src/Common/FieldVisitors.cpp index 6ca3dfd1b78..2411c1eb88c 100644 --- a/dbms/src/Common/FieldVisitors.cpp +++ b/dbms/src/Common/FieldVisitors.cpp @@ -25,6 +25,14 @@ namespace DB { +template +static inline String format(const DecimalField & x) +{ + WriteBufferFromOwnString wb; + writeText(x.getValue(), x.getScale(), wb); + return wb.str(); +} + template static inline String formatQuoted(T x) { @@ -170,19 +178,27 @@ String FieldVisitorToString::operator()(const String & x) const } String FieldVisitorToString::operator()(const DecimalField & x) const { - return formatQuoted(x); + if (isDecimalWithQuoted) + return formatQuoted(x); + return format(x); } String FieldVisitorToString::operator()(const DecimalField & x) const { - return formatQuoted(x); + if (isDecimalWithQuoted) + return formatQuoted(x); + return format(x); } String FieldVisitorToString::operator()(const DecimalField & x) const { - return formatQuoted(x); + if (isDecimalWithQuoted) + return formatQuoted(x); + return format(x); } String FieldVisitorToString::operator()(const DecimalField & x) const { - return formatQuoted(x); + if (isDecimalWithQuoted) + return formatQuoted(x); + return format(x); } String FieldVisitorToString::operator()(const Array & x) const diff --git a/dbms/src/Common/FieldVisitors.h b/dbms/src/Common/FieldVisitors.h index fb55a481ed0..b25791cc5e9 100644 --- a/dbms/src/Common/FieldVisitors.h +++ b/dbms/src/Common/FieldVisitors.h @@ -181,7 +181,16 @@ typename std::decay_t::ResultType applyVisitor(Visitor && visitor, F1 & /** Prints Field as literal in SQL query */ class FieldVisitorToString : public StaticVisitor { +private: + bool isDecimalWithQuoted; + public: + FieldVisitorToString() + : isDecimalWithQuoted(true){}; + + FieldVisitorToString(bool val) + : isDecimalWithQuoted(val){}; + String operator()(const Null & x) const; String operator()(const UInt64 & x) const; String operator()(const Int64 & x) const; diff --git a/dbms/src/TiDB/Schema/TiDB.cpp b/dbms/src/TiDB/Schema/TiDB.cpp index 933d63c3e7e..3e7133d5945 100644 --- a/dbms/src/TiDB/Schema/TiDB.cpp +++ b/dbms/src/TiDB/Schema/TiDB.cpp @@ -17,13 +17,16 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -36,6 +39,7 @@ #include #include #include +#include namespace DB { @@ -191,7 +195,8 @@ ColumnInfo::ColumnInfo(Poco::JSON::Object::Ptr json) Field ColumnInfo::defaultValueToField() const { const auto & value = origin_default_value; - if (value.isEmpty()) + const auto & bit_value = origin_default_bit_value; + if (value.isEmpty() && bit_value.isEmpty()) { if (hasNotNullFlag()) return DB::GenDefaultField(*this); @@ -223,14 +228,12 @@ Field ColumnInfo::defaultValueToField() const }); case TypeBit: { - const auto & bit_value = origin_default_bit_value; - if (bit_value.isEmpty()) - { - if (hasNotNullFlag()) - return DB::GenDefaultField(*this); - return Field(); - } - TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ return getBitValue(bit_value.convert()); }); + TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ + // When we got bit_value from tipb, we have decoded it. + if (auto is_int = bit_value.isInteger(); is_int) + return bit_value.convert(); + return getBitValue(bit_value.convert()); + }); } // Floating type. case TypeFloat: @@ -239,7 +242,12 @@ Field ColumnInfo::defaultValueToField() const case TypeDate: case TypeDatetime: case TypeTimestamp: - TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ return DB::parseMyDateTime(value.convert()); }); + TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ + // When we got value from tipb, we have decoded it. + if (auto is_int = value.isInteger(); is_int) + return value.convert(); + return DB::parseMyDateTime(value.convert()); + }); case TypeVarchar: case TypeTinyBlob: case TypeMediumBlob: @@ -277,12 +285,22 @@ Field ColumnInfo::defaultValueToField() const return getDecimalValue(text); }); case TypeTime: - TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ return getTimeValue(value.convert()); }); + TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ + // When we got value from tipb, we have decoded it. + if (auto is_int = value.isInteger(); is_int) + return value.convert(); + return getTimeValue(value.convert()); + }); case TypeYear: // Never throw exception here, do not use TRY_CATCH_DEFAULT_VALUE_TO_FIELD return getYearValue(value.convert()); case TypeSet: - TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ return getSetValue(value.convert()); }); + TRY_CATCH_DEFAULT_VALUE_TO_FIELD({ + // When we got value from tipb, we have decoded it. + if (auto is_int = value.isInteger(); is_int) + return value.convert(); + return getSetValue(value.convert()); + }); case TypeTiDBVectorFloat32: return genVectorFloat32Empty(); default: @@ -1362,17 +1380,61 @@ ColumnInfo toTiDBColumnInfo(const tipb::ColumnInfo & tipb_column_info) tidb_column_info.flag = tipb_column_info.flag(); tidb_column_info.flen = tipb_column_info.columnlen(); tidb_column_info.decimal = tipb_column_info.decimal(); - // TiFlash get default value from origin_default_value, check `Field ColumnInfo::defaultValueToField() const` - // So we need to set origin_default_value to tipb_column_info.default_val() - // Related logic in tidb, https://github.com/pingcap/tidb/blob/45318da24d8e4c0c6aab836d291a33f949dd18bf/pkg/table/tables/tables.go#L2303-L2329 - // For TypeBit, we need to set origin_default_bit_value to tipb_column_info.default_val(). - if (tidb_column_info.tp == TypeBit) - tidb_column_info.origin_default_bit_value = tipb_column_info.default_val(); - else - tidb_column_info.origin_default_value = tipb_column_info.default_val(); tidb_column_info.collate = tipb_column_info.collation(); for (int i = 0; i < tipb_column_info.elems_size(); ++i) tidb_column_info.elems.emplace_back(tipb_column_info.elems(i), i + 1); + // TiFlash get default value from origin_default_value, check `Field ColumnInfo::defaultValueToField() const` + // So we need to set origin_default_value to tipb_column_info.default_val() + // Related logic in tidb, https://github.com/pingcap/tidb/blob/45318da24d8e4c0c6aab836d291a33f949dd18bf/pkg/table/tables/tables.go#L2303-L2329 + // And, decode tipb_column_info.default_val. + { + // The default value is null. + if (tipb_column_info.default_val().empty()) + { + Poco::Dynamic::Var empty_val; + tidb_column_info.origin_default_value = empty_val; + return tidb_column_info; + } + size_t cursor = 0; + auto val = DB::DecodeDatum(cursor, tipb_column_info.default_val()); + if (val.getType() == DB::Field::Types::String) + { + tidb_column_info.origin_default_value = val.get(); + return tidb_column_info; + } + switch (tidb_column_info.tp) + { + case TypeDate: + case TypeDatetime: + case TypeTimestamp: + case TypeSet: + tidb_column_info.origin_default_value = val.get(); + break; + case TypeTime: + tidb_column_info.origin_default_value = val.get(); + break; + case TypeBit: + // For TypeBit, we need to set origin_default_bit_value to tipb_column_info.default_val(). + tidb_column_info.origin_default_bit_value = val.get(); + break; + case TypeYear: + // If the year column has 'not null' option and the value is 0, this year value is '0000'. + if (val.get() == 0) + { + Poco::Dynamic::Var empty_val; + tidb_column_info.origin_default_value = empty_val; + break; + } + // else fallthrough + // The above types will be processed again when defaultValueToField is called. + // By distinguishing the type of the string type(by synchronizing the default values in the schema, its type is string), + // we can distinguish whether it needs to be processed. + default: + auto str_val = DB::applyVisitor(DB::FieldVisitorToString(false), val); + tidb_column_info.origin_default_value = str_val; + } + } + return tidb_column_info; } diff --git a/tests/fullstack-test2/ddl/alter_default_value.test b/tests/fullstack-test2/ddl/alter_default_value.test index 80a8bfc95c0..a0385362f2b 100644 --- a/tests/fullstack-test2/ddl/alter_default_value.test +++ b/tests/fullstack-test2/ddl/alter_default_value.test @@ -103,4 +103,30 @@ mysql> set session tidb_isolation_read_engines='tiflash'; select /*+ read_from_s | 1 | Unprioritized | +------+---------------+ +mysql> alter table test.t drop column e; + +############# +# Alter table... add column with default value +mysql> alter table test.t add column col1 int default 30; +mysql> alter table test.t add column col2 year not null; +mysql> alter table test.t add column col3 decimal(6,2) not null; +mysql> alter table test.t add column col4 decimal(6,2) default "1.234"; +mysql> alter table test.t add column col5 int default 123; +mysql> alter table test.t add column col6 varchar(255) default 'sss'; +mysql> alter table test.t add column col7 timestamp default '2017-02-11'; +mysql> alter table test.t add column col8 datetime default '2018-11-04 23:12:03'; +mysql> alter table test.t add column col9 year default '2012'; +mysql> alter table test.t add column col10 set('value1', 'value2', 'value3') default 'value3'; +mysql> alter table test.t add column col11 enum('value1', 'value2', 'value3') default 'value1'; +mysql> alter table test.t add column col12 datetime default '2018-11-04 23:12:03'; +mysql> alter table test.t add column col13 time default '2017-02-23 12:18:30'; +mysql> alter table test.t add column col14 time default null; +mysql> alter table test.t add column col15 bit(32) default b'000000010000001000000011'; +mysql> set session tidb_isolation_read_engines='tiflash'; select col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12, col13, col14, hex(col15) from test.t; ++------+------+------+------+------+------+---------------------+---------------------+------+--------+--------+---------------------+----------+-------+------------+ +| col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8 | col9 | col10 | col11 | col12 | col13 | col14 | hex(col15) | ++------+------+------+------+------+------+---------------------+---------------------+------+--------+--------+---------------------+----------+-------+------------+ +| 30 | 0000 | 0.00 | 1.23 | 123 | sss | 2017-02-11 00:00:00 | 2018-11-04 23:12:03 | 2012 | value3 | value1 | 2018-11-04 23:12:03 | 12:18:30 | NULL | 10203 | +| 30 | 0000 | 0.00 | 1.23 | 123 | sss | 2017-02-11 00:00:00 | 2018-11-04 23:12:03 | 2012 | value3 | value1 | 2018-11-04 23:12:03 | 12:18:30 | NULL | 10203 | ++------+------+------+------+------+------+---------------------+---------------------+------+--------+--------+---------------------+----------+-------+------------+ mysql> drop table if exists test.t