#include #include #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_COLUMN; extern const int BAD_ARGUMENTS; extern const int LOGICAL_ERROR; } template std::vector PointFromColumnParser::parse(size_t shift, size_t count) const { const auto * tuple = typeid_cast(col.get()); const auto & tuple_columns = tuple->getColumns(); const auto * x_data = typeid_cast(tuple_columns[0].get()); const auto * y_data = typeid_cast(tuple_columns[1].get()); const auto * first_container = x_data->getData().data() + shift; const auto * second_container = y_data->getData().data() + shift; std::vector answer(count); for (size_t i = 0; i < count; ++i) { const Float64 first = first_container[i]; const Float64 second = second_container[i]; if (isNaN(first) || isNaN(second)) throw Exception("Point's component must not be NaN", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); if (isinf(first) || isinf(second)) throw Exception("Point's component must not be infinite", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); answer[i] = Point(first, second); } return answer; } template std::vector> RingFromColumnParser::parse(size_t /*shift*/, size_t /*size*/) const { size_t prev_offset = 0; std::vector> answer; answer.reserve(offsets.size()); for (size_t offset : offsets) { auto tmp = point_parser.parse(prev_offset, offset - prev_offset); answer.emplace_back(tmp.begin(), tmp.end()); prev_offset = offset; } return answer; } template std::vector> PolygonFromColumnParser::parse(size_t /*shift*/, size_t /*size*/) const { std::vector> answer(offsets.size()); auto all_rings = ring_parser.parse(0, 0); auto prev_offset = 0; for (size_t iter = 0; iter < offsets.size(); ++iter) { const auto current_array_size = offsets[iter] - prev_offset; answer[iter].outer() = std::move(all_rings[prev_offset]); answer[iter].inners().reserve(current_array_size); for (size_t inner_holes = prev_offset + 1; inner_holes < offsets[iter]; ++inner_holes) answer[iter].inners().emplace_back(std::move(all_rings[inner_holes])); prev_offset = offsets[iter]; } return answer; } template std::vector> MultiPolygonFromColumnParser::parse(size_t /*shift*/, size_t /*size*/) const { size_t prev_offset = 0; std::vector> answer(offsets.size()); auto all_polygons = polygon_parser.parse(0, 0); for (size_t iter = 0; iter < offsets.size(); ++iter) { for (size_t polygon_iter = prev_offset; polygon_iter < offsets[iter]; ++polygon_iter) answer[iter].emplace_back(std::move(all_polygons[polygon_iter])); prev_offset = offsets[iter]; } return answer; } template class ParserVisitor : public boost::static_visitor { public: template ContainterWithFigures operator()(const T & parser) const { auto parsed = parser.parse(0, 0); ContainterWithFigures figures; figures.reserve(parsed.size()); for (auto & value : parsed) figures.emplace_back(value); return figures; } }; template std::vector> parseFigure(const GeometryFromColumnParser & parser) { static ParserVisitor>> creator; return boost::apply_visitor(creator, parser); } template std::vector> parseFigure(const GeometryFromColumnParser &); template std::vector> parseFigure(const GeometryFromColumnParser &); template typename Desired> void checkColumnTypeOrThrow(const ColumnWithTypeAndName & column) { DataTypePtr desired_type; if constexpr (std::is_same_v, Ring>) desired_type = DataTypeCustomRingSerialization::nestedDataType(); else if constexpr (std::is_same_v, Polygon>) desired_type = DataTypeCustomPolygonSerialization::nestedDataType(); else if constexpr (std::is_same_v, MultiPolygon>) desired_type = DataTypeCustomMultiPolygonSerialization::nestedDataType(); else throw Exception("Unexpected Desired type.", ErrorCodes::LOGICAL_ERROR); if (!desired_type->equals(*column.type)) throw Exception(fmt::format("Expected type {} (MultiPolygon), but got {}", desired_type->getName(), column.type->getName()), ErrorCodes::BAD_ARGUMENTS); } template void checkColumnTypeOrThrow(const ColumnWithTypeAndName &); template void checkColumnTypeOrThrow(const ColumnWithTypeAndName &); template void checkColumnTypeOrThrow(const ColumnWithTypeAndName &); template void checkColumnTypeOrThrow(const ColumnWithTypeAndName &); template void checkColumnTypeOrThrow(const ColumnWithTypeAndName &); template void checkColumnTypeOrThrow(const ColumnWithTypeAndName &); template GeometryFromColumnParser getConverterBasedOnType(const ColumnWithTypeAndName & column) { if (DataTypeCustomRingSerialization::nestedDataType()->equals(*column.type)) { return RingFromColumnParser(std::move(column.column->convertToFullColumnIfConst())); } else if (DataTypeCustomPolygonSerialization::nestedDataType()->equals(*column.type)) { return PolygonFromColumnParser(std::move(column.column->convertToFullColumnIfConst())); } else if (DataTypeCustomMultiPolygonSerialization::nestedDataType()->equals(*column.type)) { return MultiPolygonFromColumnParser(std::move(column.column->convertToFullColumnIfConst())); } else { throw Exception(fmt::format("Unexpected type of column {}", column.type->getName()), ErrorCodes::BAD_ARGUMENTS); } } template GeometryFromColumnParser getConverterBasedOnType(const ColumnWithTypeAndName & column); template GeometryFromColumnParser getConverterBasedOnType(const ColumnWithTypeAndName & column); }