diff --git a/be/src/olap/schema_change.cpp b/be/src/olap/schema_change.cpp index c16ef099f04d3b..1db8780fa3d9bf 100644 --- a/be/src/olap/schema_change.cpp +++ b/be/src/olap/schema_change.cpp @@ -149,7 +149,7 @@ ColumnMapping* RowBlockChanger::get_mutable_column_mapping(size_t column_index) #define CONVERT_FROM_TYPE(from_type) \ { \ - switch (mutable_block->tablet_schema().column(i).type()) { \ + switch (newtype) { \ case OLAP_FIELD_TYPE_TINYINT: \ TYPE_REINTERPRET_CAST(from_type, int8_t); \ case OLAP_FIELD_TYPE_UNSIGNED_TINYINT: \ @@ -168,6 +168,8 @@ ColumnMapping* RowBlockChanger::get_mutable_column_mapping(size_t column_index) TYPE_REINTERPRET_CAST(from_type, uint64_t); \ case OLAP_FIELD_TYPE_LARGEINT: \ LARGEINT_REINTERPRET_CAST(from_type, int128_t); \ + case OLAP_FIELD_TYPE_FLOAT: \ + TYPE_REINTERPRET_CAST(from_type, float); \ case OLAP_FIELD_TYPE_DOUBLE: \ TYPE_REINTERPRET_CAST(from_type, double); \ default: \ @@ -217,6 +219,16 @@ class ConvertTypeResolver { }; ConvertTypeResolver::ConvertTypeResolver() { + // from char type + add_convert_type_mapping(); + add_convert_type_mapping(); + add_convert_type_mapping(); + add_convert_type_mapping(); + add_convert_type_mapping(); + add_convert_type_mapping(); + add_convert_type_mapping(); + add_convert_type_mapping(); + // supported type convert should annotate in doc: // http://doris.incubator.apache.org/master/zh-CN/sql-reference/sql-statements/Data%20Definition/ALTER%20TABLE.html#description // If type convert is supported here, you should check fe/src/main/java/org/apache/doris/catalog/ColumnType.java to supported it either @@ -239,6 +251,7 @@ ConvertTypeResolver::ConvertTypeResolver() { add_convert_type_mapping(); add_convert_type_mapping(); add_convert_type_mapping(); + add_convert_type_mapping(); add_convert_type_mapping(); @@ -452,7 +465,6 @@ OLAPStatus RowBlockChanger::change_row_block(const RowBlock* ref_block, int32_t for (size_t i = 0, len = mutable_block->tablet_schema().num_columns(); !filter_all && i < len; ++i) { int32_t ref_column = _schema_mapping[i].ref_column; - if (_schema_mapping[i].ref_column >= 0) { if (!_schema_mapping[i].materialized_function.empty()) { bool (*_do_materialized_transform) (RowCursor*, RowCursor*, const TabletColumn&, int, int, MemPool* ); @@ -523,38 +535,6 @@ OLAPStatus RowBlockChanger::change_row_block(const RowBlock* ref_block, int32_t } } } - - // 从ref_column 写入 i列。 - } else if (newtype == OLAP_FIELD_TYPE_VARCHAR && reftype == OLAP_FIELD_TYPE_CHAR) { - // 效率低下,也可以直接计算变长域拷贝,但仍然会破坏封装 - for (size_t row_index = 0, new_row_index = 0; - row_index < ref_block->row_block_info().row_num; ++row_index) { - // 不需要的row,每次处理到这个row时就跳过 - if (need_filter_data && is_data_left_vec[row_index] == 0) { - continue; - } - - // 指定新的要写入的row index(不同于读的row_index) - mutable_block->get_row(new_row_index++, &write_helper); - - ref_block->get_row(row_index, &read_helper); - - if (true == read_helper.is_null(ref_column)) { - write_helper.set_null(i); - } else { - // 要写入的 - - write_helper.set_not_null(i); - int p = ref_block->tablet_schema().column(ref_column).length() - 1; - Slice* slice = reinterpret_cast(read_helper.cell_ptr(ref_column)); - char* buf = slice->data; - while (p >= 0 && buf[p] == '\0') { - p--; - } - slice->size = p + 1; - write_helper.set_field_content(i, reinterpret_cast(slice), mem_pool); - } - } } else if (ConvertTypeResolver::instance()->get_convert_type_info(reftype, newtype)) { for (size_t row_index = 0, new_row_index = 0; row_index < ref_block->row_block_info().row_num; ++row_index) { @@ -602,6 +582,8 @@ OLAPStatus RowBlockChanger::change_row_block(const RowBlock* ref_block, int32_t CONVERT_FROM_TYPE(int64_t); case OLAP_FIELD_TYPE_UNSIGNED_BIGINT: CONVERT_FROM_TYPE(uint64_t); + case OLAP_FIELD_TYPE_LARGEINT: + CONVERT_FROM_TYPE(int128_t); default: LOG(WARNING) << "the column type which was altered from was unsupported." << " from_type=" @@ -736,10 +718,8 @@ bool RowBlockSorter::sort(RowBlock** row_block) { RowBlockAllocator::RowBlockAllocator(const TabletSchema& tablet_schema, size_t memory_limitation) : _tablet_schema(tablet_schema), _memory_allocated(0), + _row_len(tablet_schema.row_size()), _memory_limitation(memory_limitation) { - _row_len = 0; - _row_len = tablet_schema.row_size(); - VLOG(3) << "RowBlockAllocator(). row_len=" << _row_len; } diff --git a/be/src/olap/types.h b/be/src/olap/types.h index 1a44983ab08080..583e2de4fd2c57 100644 --- a/be/src/olap/types.h +++ b/be/src/olap/types.h @@ -28,6 +28,7 @@ #include "gen_cpp/segment_v2.pb.h" // for ColumnMetaPB #include "olap/collection.h" #include "olap/decimal12.h" + #include "olap/olap_common.h" #include "olap/olap_define.h" #include "olap/tablet_schema.h" // for TabletColumn @@ -495,12 +496,32 @@ struct BaseFieldtypeTraits : public CppTypeTraits { } }; +static void prepare_char_before_convert(const void* src) { + Slice* slice = const_cast(reinterpret_cast(src)); + char* buf = slice->data; + auto p = slice->size - 1; + while (p >= 0 && buf[p] == '\0') { + p--; + } + slice->size = p + 1; +} + template -OLAPStatus convert_int_from_varchar(void* dest, const void* src) { - using SrcType = typename CppTypeTraits::CppType; - auto src_value = reinterpret_cast(src); +T convert_from_varchar(const Slice* src_value, StringParser::ParseResult& parse_res, std::true_type) { + return StringParser::string_to_int(src_value->get_data(), src_value->get_size(), &parse_res); +} + +template +T convert_from_varchar(const Slice* src_value, StringParser::ParseResult& parse_res, std::false_type) { + return StringParser::string_to_float(src_value->get_data(), src_value->get_size(), &parse_res); +} + +template +OLAPStatus arithmetic_convert_from_varchar(void* dest, const void* src) { + auto src_value = reinterpret_cast(src); StringParser::ParseResult parse_res; - T result = StringParser::string_to_int(src_value->get_data(), src_value->get_size(), &parse_res); + //TODO: use C++17 if constexpr to replace label assignment + auto result = convert_from_varchar(src_value, parse_res, std::is_integral()); if (UNLIKELY(parse_res != StringParser::PARSE_SUCCESS)) { return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; } @@ -509,98 +530,55 @@ OLAPStatus convert_int_from_varchar(void* dest, const void* src) { } template -OLAPStatus convert_float_from_varchar(void* dest, const void* src) { - using SrcType = typename CppTypeTraits::CppType; - auto src_value = reinterpret_cast(src); - StringParser::ParseResult parse_res; - T result = StringParser::string_to_float(src_value->get_data(), src_value->get_size(), &parse_res); - if (UNLIKELY(parse_res != StringParser::PARSE_SUCCESS)) { - return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; - } - *reinterpret_cast(dest) = result; - return OLAPStatus::OLAP_SUCCESS; +OLAPStatus numeric_convert_from_char(void *dest, const void *src) { + prepare_char_before_convert(src); + return arithmetic_convert_from_varchar(dest, src); } -template -struct FieldTypeTraits : public BaseFieldtypeTraits { }; +// Using NumericFieldtypeTraits to Derived code for OLAP_FIELD_TYPE_XXXINT, OLAP_FIELD_TYPE_FLOAT, +// OLAP_FIELD_TYPE_DOUBLE, to reduce redundant code +template +struct NumericFieldtypeTraits : public BaseFieldtypeTraits { + using CppType = typename CppTypeTraits::CppType; -template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { static std::string to_string(const void* src) { - char buf[1024] = {'\0'}; - snprintf(buf, sizeof(buf), "%d", *reinterpret_cast(src)); - return std::string(buf); + return std::to_string(*reinterpret_cast(src)); } - static void set_to_max(void* buf) { - (*(bool*)buf) = true; - } - static void set_to_min(void* buf) { - (*(bool*)buf) = false; - } -}; -template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { - static std::string to_string(const void* src) { - char buf[1024] = {'\0'}; - snprintf(buf, sizeof(buf), "%d", *reinterpret_cast(src)); - return std::string(buf); - } static OLAPStatus convert_from(void* dest, const void* src, const TypeInfo* src_type, MemPool* mem_pool) { if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR) { - return convert_int_from_varchar(dest, src); + return arithmetic_convert_from_varchar(dest, src); + } else if (src_type->type() == OLAP_FIELD_TYPE_CHAR) { + return numeric_convert_from_char(dest, src); } return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; } }; -template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { - static std::string to_string(const void* src) { - char buf[1024] = {'\0'}; - snprintf(buf, sizeof(buf), "%d", *reinterpret_cast(src)); - return std::string(buf); - } - static OLAPStatus convert_from(void* dest, const void* src, const TypeInfo* src_type, MemPool* mem_pool) { - if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR) { - return convert_int_from_varchar(dest, src); - } - return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; - } -}; +template +struct NumericFieldtypeTraits : public BaseFieldtypeTraits {}; -template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { - static std::string to_string(const void* src) { - char buf[1024] = {'\0'}; - snprintf(buf, sizeof(buf), "%d", *reinterpret_cast(src)); - return std::string(buf); - } - static OLAPStatus convert_from(void* dest, const void* src, const TypeInfo* src_type, MemPool* mem_pool) { - if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR) { - return convert_int_from_varchar(dest, src); - } - return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; - } -}; +template +struct FieldTypeTraits : public NumericFieldtypeTraits::CppType>::value && std::is_signed::CppType>::value> {}; template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { +struct FieldTypeTraits : public BaseFieldtypeTraits { static std::string to_string(const void* src) { char buf[1024] = {'\0'}; - snprintf(buf, sizeof(buf), "%ld", *reinterpret_cast(src)); + snprintf(buf, sizeof(buf), "%d", *reinterpret_cast(src)); return std::string(buf); } - static OLAPStatus convert_from(void* dest, const void* src, const TypeInfo* src_type, MemPool* mem_pool) { - if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR) { - return convert_int_from_varchar(dest, src); - } - return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; + static void set_to_max(void* buf) { + (*(bool*)buf) = true; + } + static void set_to_min(void* buf) { + (*(bool*)buf) = false; } }; template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { +struct FieldTypeTraits : public NumericFieldtypeTraits { static OLAPStatus from_string(void* buf, const std::string& scan_key) { int128_t value = 0; @@ -699,16 +677,10 @@ struct FieldTypeTraits : public BaseFieldtypeTraits
    (buf) = (int128_t)(1) << 127; } - static OLAPStatus convert_from(void* dest, const void* src, const TypeInfo* src_type, MemPool* mem_pool) { - if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR) { - return convert_int_from_varchar(dest, src); - } - return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; - } }; template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { +struct FieldTypeTraits : public NumericFieldtypeTraits { static OLAPStatus from_string(void* buf, const std::string& scan_key) { CppType value = 0.0f; if (scan_key.length() > 0) { @@ -723,16 +695,10 @@ struct FieldTypeTraits : public BaseFieldtypeTraits= 0) << "gcvt float failed, float value=" << *reinterpret_cast(src); return std::string(buf); } - static OLAPStatus convert_from(void* dest, const void* src, const TypeInfo* src_type, MemPool* mem_pool) { - if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR) { - return convert_float_from_varchar(dest, src); - } - return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; - } }; template<> -struct FieldTypeTraits : public BaseFieldtypeTraits { +struct FieldTypeTraits : public NumericFieldtypeTraits { static OLAPStatus from_string(void* buf, const std::string& scan_key) { CppType value = 0.0; if (scan_key.length() > 0) { @@ -767,10 +733,8 @@ struct FieldTypeTraits : public BaseFieldtypeTraits(dest) = strtod(buf,&tg); return OLAPStatus::OLAP_SUCCESS; } - if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR) { - return convert_float_from_varchar(dest, src); - } - return OLAPStatus::OLAP_ERR_INVALID_SCHEMA; + + return NumericFieldtypeTraits::convert_from(dest, src, src_type, mem_pool); } }; @@ -844,7 +808,10 @@ struct FieldTypeTraits : public BaseFieldtypeTraitstype() == FieldType::OLAP_FIELD_TYPE_VARCHAR) { + if (src_type->type() == OLAP_FIELD_TYPE_VARCHAR || src_type->type() == OLAP_FIELD_TYPE_CHAR) { + if (src_type->type() == OLAP_FIELD_TYPE_CHAR) { + prepare_char_before_convert(src); + } using SrcType = typename CppTypeTraits::CppType; auto src_value = *reinterpret_cast(src); DateTimeValue dt; @@ -1032,6 +999,9 @@ struct FieldTypeTraits : public FieldTypeTraitsdata, result.c_str(), result.size()); slice->size = result.size(); return OLAP_SUCCESS; + } else if (src_type->type() == OLAP_FIELD_TYPE_CHAR) { + prepare_char_before_convert(src); + deep_copy(dest, src, mem_pool); } return OLAP_ERR_INVALID_SCHEMA; } diff --git a/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md b/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md index 1d92f712cbd268..f469bb0403be85 100644 --- a/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md +++ b/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md @@ -153,11 +153,11 @@ under the License. 3) Only the type of the column can be modified. The other attributes of the column remain as they are (ie other attributes need to be explicitly written in the statement according to the original attribute, see example 8) 4) The partition column cannot be modified 5) The following types of conversions are currently supported (accuracy loss is guaranteed by the user) - TINYINT/SMALLINT/INT/BIGINT is converted to TINYINT/SMALLINT/INT/BIGINT/DOUBLE. + TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE convert to a wider range of numeric types TINTINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE/DECIMAL is converted to VARCHAR VARCHAR supports modification of maximum length - Convert VARCHAR to TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE. - Convert VARCHAR to DATE (currently support six formats: "%Y-%m-%d", "%y-%m-%d", "%Y%m%d", "%y%m%d", "%Y/%m/%d, "%y/%m/%d") + Convert VARCHAR/CHAR to TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE. + Convert VARCHAR/CHAR to DATE (currently support six formats: "%Y-%m-%d", "%y-%m-%d", "%Y%m%d", "%y%m%d", "%Y/%m/%d, "%y/%m/%d") Convert DATETIME to DATE(Only year-month-day information is retained, For example: `2019-12-09 21:47:05` <--> `2019-12-09`) Convert DATE to DATETIME(Set hour, minute, second to zero, For example: `2019-12-09` <--> `2019-12-09 00:00:00`) Convert FLOAT to DOUBLE diff --git a/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md b/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md index a0bb66d011ffc0..32e43a43b0f469 100644 --- a/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md +++ b/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md @@ -151,11 +151,11 @@ under the License. 3) 只能修改列的类型,列的其他属性维持原样(即其他属性需在语句中按照原属性显式的写出,参见 example 8) 4) 分区列不能做任何修改 5) 目前支持以下类型的转换(精度损失由用户保证) - TINYINT/SMALLINT/INT/BIGINT 转换成 TINYINT/SMALLINT/INT/BIGINT/DOUBLE。 + TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE 类型向范围更大的数字类型转换 TINTINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE/DECIMAL 转换成 VARCHAR VARCHAR 支持修改最大长度 - VARCHAR 转换成 TINTINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE - VARCHAR 转换成 DATE (目前支持"%Y-%m-%d", "%y-%m-%d", "%Y%m%d", "%y%m%d", "%Y/%m/%d, "%y/%m/%d"六种格式化格式) + VARCHAR/CHAR 转换成 TINTINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE + VARCHAR/CHAR 转换成 DATE (目前支持"%Y-%m-%d", "%y-%m-%d", "%Y%m%d", "%y%m%d", "%Y/%m/%d, "%y/%m/%d"六种格式化格式) DATETIME 转换成 DATE(仅保留年-月-日信息, 例如: `2019-12-09 21:47:05` <--> `2019-12-09`) DATE 转换成 DATETIME(时分秒自动补零, 例如: `2019-12-09` <--> `2019-12-09 00:00:00`) FLOAT 转换成 DOUBLE diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/ColumnType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/ColumnType.java index f27e4149019028..f6f1b4c49d0bcf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/ColumnType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/ColumnType.java @@ -46,25 +46,31 @@ public abstract class ColumnType { schemaChangeMatrix[PrimitiveType.TINYINT.ordinal()][PrimitiveType.INT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.TINYINT.ordinal()][PrimitiveType.BIGINT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.TINYINT.ordinal()][PrimitiveType.LARGEINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.TINYINT.ordinal()][PrimitiveType.FLOAT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.TINYINT.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; schemaChangeMatrix[PrimitiveType.TINYINT.ordinal()][PrimitiveType.VARCHAR.ordinal()] = true; schemaChangeMatrix[PrimitiveType.SMALLINT.ordinal()][PrimitiveType.INT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.SMALLINT.ordinal()][PrimitiveType.BIGINT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.SMALLINT.ordinal()][PrimitiveType.LARGEINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.SMALLINT.ordinal()][PrimitiveType.FLOAT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.SMALLINT.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; schemaChangeMatrix[PrimitiveType.SMALLINT.ordinal()][PrimitiveType.VARCHAR.ordinal()] = true; schemaChangeMatrix[PrimitiveType.INT.ordinal()][PrimitiveType.BIGINT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.INT.ordinal()][PrimitiveType.LARGEINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.INT.ordinal()][PrimitiveType.FLOAT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.INT.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; schemaChangeMatrix[PrimitiveType.INT.ordinal()][PrimitiveType.DATE.ordinal()] = true; schemaChangeMatrix[PrimitiveType.INT.ordinal()][PrimitiveType.VARCHAR.ordinal()] = true; schemaChangeMatrix[PrimitiveType.BIGINT.ordinal()][PrimitiveType.LARGEINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.BIGINT.ordinal()][PrimitiveType.FLOAT.ordinal()] = true; schemaChangeMatrix[PrimitiveType.BIGINT.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; schemaChangeMatrix[PrimitiveType.BIGINT.ordinal()][PrimitiveType.VARCHAR.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.LARGEINT.ordinal()][PrimitiveType.FLOAT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.LARGEINT.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; schemaChangeMatrix[PrimitiveType.LARGEINT.ordinal()][PrimitiveType.VARCHAR.ordinal()] = true; schemaChangeMatrix[PrimitiveType.FLOAT.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; @@ -84,6 +90,15 @@ public abstract class ColumnType { schemaChangeMatrix[PrimitiveType.VARCHAR.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; schemaChangeMatrix[PrimitiveType.VARCHAR.ordinal()][PrimitiveType.DATE.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.TINYINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.SMALLINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.INT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.BIGINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.LARGEINT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.FLOAT.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.DOUBLE.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.CHAR.ordinal()][PrimitiveType.DATE.ordinal()] = true; + schemaChangeMatrix[PrimitiveType.DECIMAL.ordinal()][PrimitiveType.VARCHAR.ordinal()] = true; schemaChangeMatrix[PrimitiveType.DECIMALV2.ordinal()][PrimitiveType.VARCHAR.ordinal()] = true;