NamesAndTypesList getStructureOfRemoteTable( const Cluster & cluster, const std::string & database, const std::string & table, const Context & context) { /// Запрос на описание таблицы String query = "DESC TABLE " + backQuoteIfNeed(database) + "." + backQuoteIfNeed(table); Settings settings = context.getSettings(); NamesAndTypesList res; /// Отправляем на первый попавшийся удалённый шард. const auto & shard_info = cluster.getAnyShardInfo(); if (shard_info.isLocal()) return context.getTable(database, table)->getColumnsList(); ConnectionPoolPtr pool = shard_info.pool; BlockInputStreamPtr input = std::make_shared<RemoteBlockInputStream>( pool.get(), query, &settings, nullptr, Tables(), QueryProcessingStage::Complete, context); input->readPrefix(); const DataTypeFactory & data_type_factory = DataTypeFactory::instance(); while (Block current = input->read()) { ColumnPtr name = current.getByName("name").column; ColumnPtr type = current.getByName("type").column; size_t size = name->size(); for (size_t i = 0; i < size; ++i) { String column_name = (*name)[i].get<const String &>(); String data_type_name = (*type)[i].get<const String &>(); res.emplace_back(column_name, data_type_factory.get(data_type_name)); } } return res; }
ColumnPtr recursiveLowCardinalityConversion(const ColumnPtr & column, const DataTypePtr & from_type, const DataTypePtr & to_type) { if (!column) return column; if (from_type->equals(*to_type)) return column; if (const auto * column_const = typeid_cast<const ColumnConst *>(column.get())) return ColumnConst::create(recursiveLowCardinalityConversion(column_const->getDataColumnPtr(), from_type, to_type), column_const->size()); if (const auto * low_cardinality_type = typeid_cast<const DataTypeLowCardinality *>(from_type.get())) { if (to_type->equals(*low_cardinality_type->getDictionaryType())) return column->convertToFullColumnIfLowCardinality(); } if (const auto * low_cardinality_type = typeid_cast<const DataTypeLowCardinality *>(to_type.get())) { if (from_type->equals(*low_cardinality_type->getDictionaryType())) { auto col = low_cardinality_type->createColumn(); static_cast<ColumnLowCardinality &>(*col).insertRangeFromFullColumn(*column, 0, column->size()); return std::move(col); } } if (const auto * from_array_type = typeid_cast<const DataTypeArray *>(from_type.get())) { if (const auto * to_array_type = typeid_cast<const DataTypeArray *>(to_type.get())) { const auto * column_array = typeid_cast<const ColumnArray *>(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<const DataTypeTuple *>(from_type.get())) { if (const auto * to_tuple_type = typeid_cast<const DataTypeTuple *>(to_type.get())) { const auto * column_tuple = typeid_cast<const ColumnTuple *>(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); }