#include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_COLUMN; extern const int TYPE_MISMATCH; } DataTypePtr recursiveRemoveLowCardinality(const DataTypePtr & type) { if (!type) return type; if (const auto * array_type = typeid_cast(type.get())) return std::make_shared(recursiveRemoveLowCardinality(array_type->getNestedType())); if (const auto * tuple_type = typeid_cast(type.get())) { DataTypes elements = tuple_type->getElements(); for (auto & element : elements) element = recursiveRemoveLowCardinality(element); if (tuple_type->haveExplicitNames()) return std::make_shared(elements, tuple_type->getElementNames()); else return std::make_shared(elements); } if (const auto * low_cardinality_type = typeid_cast(type.get())) return low_cardinality_type->getDictionaryType(); return type; } ColumnPtr recursiveRemoveLowCardinality(const ColumnPtr & column) { if (!column) return column; if (const auto * column_array = typeid_cast(column.get())) return ColumnArray::create(recursiveRemoveLowCardinality(column_array->getDataPtr()), column_array->getOffsetsPtr()); if (const auto * column_const = typeid_cast(column.get())) return ColumnConst::create(recursiveRemoveLowCardinality(column_const->getDataColumnPtr()), column_const->size()); if (const auto * column_tuple = typeid_cast(column.get())) { Columns columns = column_tuple->getColumns(); for (auto & element : columns) element = recursiveRemoveLowCardinality(element); return ColumnTuple::create(columns); } if (const auto * column_low_cardinality = typeid_cast(column.get())) return column_low_cardinality->convertToFullColumn(); return column; } ColumnPtr recursiveLowCardinalityConversion(const ColumnPtr & column, const DataTypePtr & from_type, const DataTypePtr & to_type) { if (from_type->equals(*to_type)) return column; if (const auto * column_const = typeid_cast(column.get())) return ColumnConst::create(recursiveLowCardinalityConversion(column_const->getDataColumnPtr(), from_type, to_type), column_const->size()); if (const auto * low_cardinality_type = typeid_cast(from_type.get())) { if (to_type->equals(*low_cardinality_type->getDictionaryType())) return column->convertToFullColumnIfLowCardinality(); } if (const auto * low_cardinality_type = typeid_cast(to_type.get())) { if (from_type->equals(*low_cardinality_type->getDictionaryType())) { auto col = low_cardinality_type->createColumn(); static_cast(*col).insertRangeFromFullColumn(*column, 0, column->size()); return std::move(col); } } if (const auto * from_array_type = typeid_cast(from_type.get())) { if (const auto * to_array_type = typeid_cast(to_type.get())) { const auto * column_array = typeid_cast(column.get()); if (!column_array) throw Exception("Unexpected column " + column->getName() + " for type " + from_type->getName(), ErrorCodes::ILLEGAL_COLUMN); auto & nested_from = from_array_type->getNestedType(); auto & nested_to = to_array_type->getNestedType(); return ColumnArray::create( recursiveLowCardinalityConversion(column_array->getDataPtr(), nested_from, nested_to), column_array->getOffsetsPtr()); } } if (const auto * from_tuple_type = typeid_cast(from_type.get())) { if (const auto * to_tuple_type = typeid_cast(to_type.get())) { const auto * column_tuple = typeid_cast(column.get()); if (!column_tuple) throw Exception("Unexpected column " + column->getName() + " for type " + from_type->getName(), ErrorCodes::ILLEGAL_COLUMN); Columns columns = column_tuple->getColumns(); auto & from_elements = from_tuple_type->getElements(); auto & to_elements = to_tuple_type->getElements(); for (size_t i = 0; i < columns.size(); ++i) { auto & element = columns[i]; element = recursiveLowCardinalityConversion(element, from_elements.at(i), to_elements.at(i)); } return ColumnTuple::create(columns); } } throw Exception("Cannot convert: " + from_type->getName() + " to " + to_type->getName(), ErrorCodes::TYPE_MISMATCH); } }