diff --git a/dbms/src/Columns/ColumnWithDictionary.h b/dbms/src/Columns/ColumnWithDictionary.h index 38fffebda58..dbb89c74ec1 100644 --- a/dbms/src/Columns/ColumnWithDictionary.h +++ b/dbms/src/Columns/ColumnWithDictionary.h @@ -72,12 +72,36 @@ public: } void insert(const Field & x) override { getIndexes()->insert(Field(UInt64(getUnique()->uniqueInsert(x)))); } - void insertFrom(const IColumn & src, size_t n) override { getIndexes()->insert(getUnique()->uniqueInsertFrom(src, n)); } - void insertRangeFrom(const IColumn & src, size_t start, size_t length) override + + void insertFromFullColumn(const IColumn & src, size_t n) + { + getIndexes()->insert(getUnique()->uniqueInsertFrom(src, n)); + } + void insertFrom(const IColumn & src, size_t n) override + { + if (!typeid_cast(&src)) + throw Exception("Expected ColumnWithDictionary, got" + src.getName(), ErrorCodes::ILLEGAL_COLUMN); + auto & src_with_dict = static_cast(src); + size_t idx = src_with_dict.getIndexes()->getUInt(n); + insertFromFullColumn(*src_with_dict.getUnique()->getNestedColumn(), idx); + } + + void insertRangeFromFullColumn(const IColumn & src, size_t start, size_t length) { auto inserted_indexes = getUnique()->uniqueInsertRangeFrom(src, start, length); getIndexes()->insertRangeFrom(*inserted_indexes, 0, length); } + void insertRangeFrom(const IColumn & src, size_t start, size_t length) override + { + if (!typeid_cast(&src)) + throw Exception("Expected ColumnWithDictionary, got" + src.getName(), ErrorCodes::ILLEGAL_COLUMN); + + auto & src_with_dict = static_cast(src); + auto & src_nested = src_with_dict.getUnique()->getNestedColumn(); + auto inserted_idx = getUnique()->uniqueInsertRangeFrom(*src_nested, 0, src_nested->size()); + auto idx = inserted_idx->index(src_with_dict.getIndexes()->cut(start, length), 0); + getIndexes()->insertRangeFrom(*idx, 0, length); + } void insertData(const char * pos, size_t length) override { diff --git a/dbms/src/DataTypes/DataTypeWithDictionary.cpp b/dbms/src/DataTypes/DataTypeWithDictionary.cpp index cf7f10dd681..1ede81241ff 100644 --- a/dbms/src/DataTypes/DataTypeWithDictionary.cpp +++ b/dbms/src/DataTypes/DataTypeWithDictionary.cpp @@ -145,9 +145,7 @@ void DataTypeWithDictionary::deserializeImpl( (dictionary_type.get()->*func)(*temp_column, istr, std::forward(args)...); - /// Note: Insertion into ColumnWithDictionary from it's nested column may cause insertion from column to itself. - /// Generally it's wrong because column may reallocate memory before insertion. - column_with_dictionary.insertFrom(*temp_column, 0); + column_with_dictionary.insertFromFullColumn(*temp_column, 0); } template diff --git a/dbms/src/Functions/IFunction.cpp b/dbms/src/Functions/IFunction.cpp index dbf9136fc04..c15eca35e90 100644 --- a/dbms/src/Functions/IFunction.cpp +++ b/dbms/src/Functions/IFunction.cpp @@ -306,24 +306,15 @@ void PreparedFunctionImpl::execute(Block & block, const ColumnNumbers & args, si executeWithoutColumnsWithDictionary(temp_block, temp_numbers, 0); auto & temp_res_col = temp_block.getByPosition(0).column; auto & res_col = block.getByPosition(result); - res_col.column = res_col.type->createColumn(); + auto col_wit_dict_ptr = res_col.type->createColumn(); - auto * col_with_dict = checkAndGetColumn(res_col.column.get()); + auto * col_with_dict = typeid_cast(col_wit_dict_ptr.get()); if (!col_with_dict) throw Exception("Expected ColumnWithDictionary, got" + res_col.column->getName(), ErrorCodes::LOGICAL_ERROR); - auto & mut_col_with_dict = const_cast(*col_with_dict); - - if (indexes) - { - auto new_ind = mut_col_with_dict.getUnique()->uniqueInsertRangeFrom(*temp_res_col, 0, temp_res_col->size()); - mut_col_with_dict.setIndexes(new_ind->index(indexes, 0)->assumeMutable()); - } - else - { - mut_col_with_dict.insertRangeFrom(*temp_res_col, 0, temp_res_col->size()); - } + col_with_dict->insertRangeFromFullColumn(*temp_res_col, 0, temp_res_col->size()); + res_col.column = indexes ? col_with_dict->index(indexes, 0) : std::move(col_wit_dict_ptr); return; } }