From 229fffcd56414727fc806c711b7ca8d16f876878 Mon Sep 17 00:00:00 2001 From: Alexis Arnaud Date: Tue, 6 Aug 2024 19:31:30 +0200 Subject: [PATCH] post-review changes --- src/Core/SettingsChangesHistory.cpp | 1 + .../Serializations/SerializationArray.cpp | 104 +--------------- .../Serializations/SerializationMap.cpp | 99 +-------------- .../Serializations/SerializationTuple.cpp | 116 +++--------------- .../Serializations/SerializationTuple.h | 3 + src/Formats/FormatFactory.cpp | 1 - src/Formats/JSONUtils.cpp | 31 ++--- src/Formats/JSONUtils.h | 109 ++++++++++++++++ 8 files changed, 154 insertions(+), 310 deletions(-) diff --git a/src/Core/SettingsChangesHistory.cpp b/src/Core/SettingsChangesHistory.cpp index 2f99910d7a0..e385f72fb38 100644 --- a/src/Core/SettingsChangesHistory.cpp +++ b/src/Core/SettingsChangesHistory.cpp @@ -89,6 +89,7 @@ static std::initializer_list #include #include -#include #include #include #include #include #include +#include namespace DB { @@ -620,108 +620,16 @@ namespace template ReturnType deserializeTextJSONArrayImpl(IColumn & column, ReadBuffer & istr, const SerializationPtr & nested, const FormatSettings & settings) { - static constexpr auto throw_exception = std::is_same_v; - - static constexpr auto EMPTY_STRING = "\"\""; - static constexpr auto EMPTY_STRING_LENGTH = std::string_view(EMPTY_STRING).length(); - - auto do_deserialize_nested = [](IColumn & nested_column, ReadBuffer & buf, auto && check_for_empty_string, auto && deserialize) -> ReturnType + auto deserializer = [&nested](IColumn & column_, ReadBuffer & istr_, auto && deserialize_nested) -> ReturnType { - if (check_for_empty_string(buf)) + auto adapter = [&deserialize_nested, &istr_, &nested](IColumn & nested_column) -> ReturnType { - nested_column.insertDefault(); - return ReturnType(true); - } - return deserialize(nested_column, buf); - }; - - auto deserialize_nested_impl = [&settings, &nested](IColumn & nested_column, ReadBuffer & buf) -> ReturnType - { - if constexpr (throw_exception) - { - if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(nested_column)) - SerializationNullable::deserializeNullAsDefaultOrNestedTextJSON(nested_column, buf, settings, nested); - else - nested->deserializeTextJSON(nested_column, buf, settings); - return; - } - else - { - if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(nested_column)) - return SerializationNullable::tryDeserializeNullAsDefaultOrNestedTextJSON(nested_column, buf, settings, nested); - else - return nested->tryDeserializeTextJSON(nested_column, buf, settings); - } - }; - - auto deserialize_nested = [&settings, &do_deserialize_nested, &deserialize_nested_impl](IColumn & nested_column, ReadBuffer & buf) -> ReturnType - { - if (!settings.json.empty_as_default || buf.eof() || *buf.position() != EMPTY_STRING[0]) - return deserialize_nested_impl(nested_column, buf); - - if (buf.available() >= EMPTY_STRING_LENGTH) - { - /// We have enough data in buffer to check if we have an empty string. - auto check_for_empty_string = [](ReadBuffer & buf_) -> bool - { - auto * pos = buf_.position(); - if (checkString(EMPTY_STRING, buf_)) - return true; - else - { - buf_.position() = pos; - return false; - } - }; - - return do_deserialize_nested(nested_column, buf, check_for_empty_string, deserialize_nested_impl); - } - - /// We don't have enough data in buffer to check if we have an empty string. - /// Use PeekableReadBuffer to make a checkpoint before checking for an - /// empty string and rollback if check was failed. - - auto check_for_empty_string = [](ReadBuffer & buf_) -> bool - { - auto & peekable_buf = assert_cast(buf_); - peekable_buf.setCheckpoint(); - SCOPE_EXIT(peekable_buf.dropCheckpoint()); - if (checkString(EMPTY_STRING, peekable_buf)) - return true; - else - { - peekable_buf.rollbackToCheckpoint(); - return false; - } + return deserialize_nested(nested_column, istr_, nested); }; - - auto deserialize_nested_impl_with_check = [&deserialize_nested_impl](IColumn & nested_column_, ReadBuffer & buf_) -> ReturnType - { - auto & peekable_buf = assert_cast(buf_); - if constexpr (throw_exception) - { - deserialize_nested_impl(nested_column_, peekable_buf); - assert(!peekable_buf.hasUnreadData()); - } - else - { - if (!deserialize_nested_impl(nested_column_, peekable_buf)) - return false; - if (likely(!peekable_buf.hasUnreadData())) - return true; - return false; - } - }; - - PeekableReadBuffer peekable_buf(buf, true); - return do_deserialize_nested(nested_column, peekable_buf, check_for_empty_string, deserialize_nested_impl_with_check); + return deserializeTextImpl(column_, istr_, adapter, false); }; - return deserializeTextImpl(column, istr, - [&deserialize_nested, &istr](IColumn & nested_column) -> ReturnType - { - return deserialize_nested(nested_column, istr); - }, false); + return JSONUtils::deserializeEmpyStringAsDefaultOrNested(column, istr, settings, deserializer); } } diff --git a/src/DataTypes/Serializations/SerializationMap.cpp b/src/DataTypes/Serializations/SerializationMap.cpp index 4a9f701c5c1..0412a85ee44 100644 --- a/src/DataTypes/Serializations/SerializationMap.cpp +++ b/src/DataTypes/Serializations/SerializationMap.cpp @@ -6,9 +6,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -319,103 +319,16 @@ void SerializationMap::serializeTextJSONPretty(const IColumn & column, size_t ro template ReturnType SerializationMap::deserializeTextJSONMapImpl(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const { - static constexpr auto throw_exception = std::is_same_v; - - static constexpr auto EMPTY_STRING = "\"\""; - static constexpr auto EMPTY_STRING_LENGTH = std::string_view(EMPTY_STRING).length(); - - auto do_deserialize_subcolumn = [](ReadBuffer & buf, const SerializationPtr & subcolumn_serialization, IColumn & subcolumn, auto && check_for_empty_string, auto && deserialize) -> ReturnType + auto deserializer = [this](IColumn & column_, ReadBuffer & istr_, auto && deserialize_nested) -> ReturnType { - if (check_for_empty_string(buf)) + auto adapter = [&deserialize_nested](ReadBuffer & buf, const SerializationPtr & nested_column_serialization, IColumn & nested_column) -> ReturnType { - subcolumn.insertDefault(); - return ReturnType(true); - } - return deserialize(buf, subcolumn_serialization, subcolumn); - }; - - auto deserialize_subcolumn_impl = [&settings](ReadBuffer & buf, const SerializationPtr & subcolumn_serialization, IColumn & subcolumn) -> ReturnType - { - if constexpr (throw_exception) - { - if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(subcolumn)) - SerializationNullable::deserializeNullAsDefaultOrNestedTextJSON(subcolumn, buf, settings, subcolumn_serialization); - else - subcolumn_serialization->deserializeTextJSON(subcolumn, buf, settings); - } - else - { - if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(subcolumn)) - return SerializationNullable::tryDeserializeNullAsDefaultOrNestedTextJSON(subcolumn, buf, settings, subcolumn_serialization); - else - return subcolumn_serialization->tryDeserializeTextJSON(subcolumn, buf, settings); - } - }; - - auto deserialize_subcolumn = [&settings, &do_deserialize_subcolumn, &deserialize_subcolumn_impl](ReadBuffer & buf, const SerializationPtr & subcolumn_serialization, IColumn & subcolumn) -> ReturnType - { - if (!settings.json.empty_as_default || buf.eof() || *buf.position() != EMPTY_STRING[0]) - return do_deserialize_subcolumn(buf, subcolumn_serialization, subcolumn, [](ReadBuffer &){ return false; }, deserialize_subcolumn_impl); - - if (buf.available() >= EMPTY_STRING_LENGTH) - { - /// We have enough data in buffer to check if we have an empty string. - auto check_for_empty_string = [](ReadBuffer & buf_) -> bool - { - auto * pos = buf_.position(); - if (checkString(EMPTY_STRING, buf_)) - return true; - else - { - buf_.position() = pos; - return false; - } - }; - - return do_deserialize_subcolumn(buf, subcolumn_serialization, subcolumn, check_for_empty_string, deserialize_subcolumn_impl); - } - - /// We don't have enough data in buffer to check if we have an empty string. - /// Use PeekableReadBuffer to make a checkpoint before checking for an - /// empty string and rollback if check was failed. - - auto check_for_empty_string = [](ReadBuffer & buf_) -> bool - { - auto & peekable_buf = assert_cast(buf_); - peekable_buf.setCheckpoint(); - SCOPE_EXIT(peekable_buf.dropCheckpoint()); - if (checkString(EMPTY_STRING, peekable_buf)) - return true; - else - { - peekable_buf.rollbackToCheckpoint(); - return false; - } + return deserialize_nested(nested_column, buf, nested_column_serialization); }; - - auto deserialize_subcolumn_impl_with_check = [&deserialize_subcolumn_impl](ReadBuffer & buf_, const SerializationPtr & subcolumn_serialization_, IColumn & subcolumn_) -> ReturnType - { - auto & peekable_buf = assert_cast(buf_); - if constexpr (throw_exception) - { - deserialize_subcolumn_impl(peekable_buf, subcolumn_serialization_, subcolumn_); - assert(!peekable_buf.hasUnreadData()); - } - else - { - if (!deserialize_subcolumn_impl(peekable_buf, subcolumn_serialization_, subcolumn_)) - return false; - if (likely(!peekable_buf.hasUnreadData())) - return true; - return false; - } - }; - - PeekableReadBuffer peekable_buf(buf, true); - return do_deserialize_subcolumn(peekable_buf, subcolumn_serialization, subcolumn, check_for_empty_string, deserialize_subcolumn_impl_with_check); + return this->deserializeTextImpl(column_, istr_, adapter); }; - return deserializeTextImpl(column, istr, deserialize_subcolumn); + return JSONUtils::deserializeEmpyStringAsDefaultOrNested(column, istr, settings, deserializer); } void SerializationMap::deserializeTextJSON(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const diff --git a/src/DataTypes/Serializations/SerializationTuple.cpp b/src/DataTypes/Serializations/SerializationTuple.cpp index 7238c2bdbd7..459677d40cd 100644 --- a/src/DataTypes/Serializations/SerializationTuple.cpp +++ b/src/DataTypes/Serializations/SerializationTuple.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -314,103 +314,9 @@ void SerializationTuple::serializeTextJSONPretty(const IColumn & column, size_t } template -ReturnType SerializationTuple::deserializeTextJSONImpl(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const +ReturnType SerializationTuple::deserializeTextJSONTupleImpl(IColumn & column, ReadBuffer & istr, const FormatSettings & settings, auto && deserialize_element) const { - static constexpr bool throw_exception = std::is_same_v; - - static constexpr auto EMPTY_STRING = "\"\""; - static constexpr auto EMPTY_STRING_LENGTH = std::string_view(EMPTY_STRING).length(); - - auto do_deserialize_element = [](IColumn & element_column, size_t element_pos, ReadBuffer & buf, auto && check_for_empty_string, auto && deserialize) -> ReturnType - { - if (check_for_empty_string(buf)) - { - element_column.insertDefault(); - return ReturnType(true); - } - - return deserialize(element_column, element_pos, buf); - }; - - auto deserialize_element_impl = [&settings, this](IColumn & element_column, size_t element_pos, ReadBuffer & buf) -> ReturnType - { - if constexpr (throw_exception) - { - if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(element_column)) - SerializationNullable::deserializeNullAsDefaultOrNestedTextJSON(element_column, buf, settings, elems[element_pos]); - else - elems[element_pos]->deserializeTextJSON(element_column, buf, settings); - } - else - { - if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(element_column)) - return SerializationNullable::tryDeserializeNullAsDefaultOrNestedTextJSON(element_column, buf, settings, elems[element_pos]); - return elems[element_pos]->tryDeserializeTextJSON(element_column, buf, settings); - } - }; - - auto deserialize_element = [&settings, &do_deserialize_element, &deserialize_element_impl, &istr](IColumn & element_column, size_t element_pos) -> ReturnType - { - if (!settings.json.empty_as_default || istr.eof() || *istr.position() != EMPTY_STRING[0]) - return do_deserialize_element(element_column, element_pos, istr, [](ReadBuffer &) { return false; }, deserialize_element_impl); - - if (istr.available() >= EMPTY_STRING_LENGTH) - { - /// We have enough data in buffer to check if we have an empty string. - auto check_for_empty_string = [](ReadBuffer & buf_) -> bool - { - auto * pos = buf_.position(); - if (checkString(EMPTY_STRING, buf_)) - return true; - else - { - buf_.position() = pos; - return false; - } - }; - - return do_deserialize_element(element_column, element_pos, istr, check_for_empty_string, deserialize_element_impl); - } - - /// We don't have enough data in buffer to check if we have an empty string. - /// Use PeekableReadBuffer to make a checkpoint before checking for an - /// empty string and rollback if check was failed. - - auto check_for_empty_string = [](ReadBuffer & buf_) -> bool - { - auto & peekable_buf = assert_cast(buf_); - peekable_buf.setCheckpoint(); - SCOPE_EXIT(peekable_buf.dropCheckpoint()); - if (checkString(EMPTY_STRING, peekable_buf)) - return true; - else - { - peekable_buf.rollbackToCheckpoint(); - return false; - } - }; - - auto deserialize_element_impl_with_check = [&deserialize_element_impl](IColumn & element_column_, size_t element_pos_, ReadBuffer & buf_) -> ReturnType - { - auto & peekable_buf = assert_cast(buf_); - if constexpr (throw_exception) - { - deserialize_element_impl(element_column_, element_pos_, peekable_buf); - assert(!peekable_buf.hasUnreadData()); - } - else - { - if (!deserialize_element_impl(element_column_, element_pos_, peekable_buf)) - return false; - if (likely(!peekable_buf.hasUnreadData())) - return true; - return false; - } - }; - - PeekableReadBuffer peekable_buf(istr, true); - return do_deserialize_element(element_column, element_pos, peekable_buf, check_for_empty_string, deserialize_element_impl_with_check); - }; + static constexpr auto throw_exception = std::is_same_v; if (settings.json.read_named_tuples_as_objects && have_explicit_names) @@ -583,6 +489,22 @@ ReturnType SerializationTuple::deserializeTextJSONImpl(IColumn & column, ReadBuf } } +template +ReturnType SerializationTuple::deserializeTextJSONImpl(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const +{ + auto deserializer = [&settings, this](IColumn & column_, ReadBuffer & istr_, auto && deserialize_nested) -> ReturnType + { + auto adapter = [&deserialize_nested, &istr_, this](IColumn & nested_column, size_t element_pos) -> ReturnType + { + return deserialize_nested(nested_column, istr_, this->elems[element_pos]); + }; + + return this->deserializeTextJSONTupleImpl(column_, istr_, settings, adapter); + }; + + return JSONUtils::deserializeEmpyStringAsDefaultOrNested(column, istr, settings, deserializer); +} + void SerializationTuple::deserializeTextJSON(DB::IColumn & column, DB::ReadBuffer & istr, const DB::FormatSettings & settings) const { deserializeTextJSONImpl(column, istr, settings); diff --git a/src/DataTypes/Serializations/SerializationTuple.h b/src/DataTypes/Serializations/SerializationTuple.h index 810673d8b21..4a55ea6eedf 100644 --- a/src/DataTypes/Serializations/SerializationTuple.h +++ b/src/DataTypes/Serializations/SerializationTuple.h @@ -81,6 +81,9 @@ private: template ReturnType deserializeTextImpl(IColumn & column, ReadBuffer & istr, const FormatSettings & settings, bool whole) const; + template + ReturnType deserializeTextJSONTupleImpl(IColumn & column, ReadBuffer & istr, const FormatSettings & settings, auto && deserialize_element) const; + template ReturnType deserializeTextJSONImpl(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const; diff --git a/src/Formats/FormatFactory.cpp b/src/Formats/FormatFactory.cpp index 59131f34697..c1723a65e6d 100644 --- a/src/Formats/FormatFactory.cpp +++ b/src/Formats/FormatFactory.cpp @@ -151,7 +151,6 @@ FormatSettings getFormatSettings(const ContextPtr & context, const Settings & se format_settings.json.try_infer_objects_as_tuples = settings.input_format_json_try_infer_named_tuples_from_objects; format_settings.json.throw_on_bad_escape_sequence = settings.input_format_json_throw_on_bad_escape_sequence; format_settings.json.ignore_unnecessary_fields = settings.input_format_json_ignore_unnecessary_fields; - format_settings.json.case_insensitive_column_matching = settings.input_format_json_case_insensitive_column_matching; format_settings.json.empty_as_default = settings.input_format_json_empty_as_default; format_settings.null_as_default = settings.input_format_null_as_default; format_settings.force_null_for_omitted_fields = settings.input_format_force_null_for_omitted_fields; diff --git a/src/Formats/JSONUtils.cpp b/src/Formats/JSONUtils.cpp index 34f55ef00d8..4f0187b4d87 100644 --- a/src/Formats/JSONUtils.cpp +++ b/src/Formats/JSONUtils.cpp @@ -3,10 +3,7 @@ #include #include #include -#include -#include #include -#include #include #include #include @@ -311,8 +308,8 @@ namespace JSONUtils return true; }; - if (!format_settings.json.empty_as_default || in.eof() || *in.position() != EMPTY_STRING[0]) - return do_deserialize(column, in, [](ReadBuffer &) { return false; }, deserialize_impl); + if (!format_settings.json.empty_as_default || in.eof() || *in.position() != EMPTY_STRING[0]) + return deserialize_impl(column, in); if (in.available() >= EMPTY_STRING_LENGTH) { @@ -322,11 +319,8 @@ namespace JSONUtils auto * pos = buf_.position(); if (checkString(EMPTY_STRING, buf_)) return true; - else - { - buf_.position() = pos; - return false; - } + buf_.position() = pos; + return false; }; return do_deserialize(column, in, check_for_empty_string, deserialize_impl); @@ -343,22 +337,17 @@ namespace JSONUtils SCOPE_EXIT(peekable_buf.dropCheckpoint()); if (checkString(EMPTY_STRING, peekable_buf)) return true; - else - { - peekable_buf.rollbackToCheckpoint(); - return false; - } + peekable_buf.rollbackToCheckpoint(); + return false; }; auto deserialize_impl_with_check = [&deserialize_impl](IColumn & column_, ReadBuffer & buf_) -> bool { auto & peekable_buf = assert_cast(buf_); - - if (!deserialize_impl(column_, peekable_buf)) - return false; - if (likely(!peekable_buf.hasUnreadData())) - return true; - return false; + bool res = deserialize_impl(column_, peekable_buf); + if (unlikely(peekable_buf.hasUnreadData())) + throw Exception(ErrorCodes::LOGICAL_ERROR, "Incorrect state while parsing JSON: PeekableReadBuffer has unread data in own memory: {}", String(peekable_buf.position(), peekable_buf.available())); + return res; }; PeekableReadBuffer peekable_buf(in, true); diff --git a/src/Formats/JSONUtils.h b/src/Formats/JSONUtils.h index e2ac3467971..2800017bfed 100644 --- a/src/Formats/JSONUtils.h +++ b/src/Formats/JSONUtils.h @@ -2,11 +2,15 @@ #include #include +#include #include #include +#include #include +#include #include #include +#include #include #include @@ -16,6 +20,11 @@ namespace DB class Block; struct JSONInferenceInfo; +namespace ErrorCodes +{ + extern const int LOGICAL_ERROR; +} + namespace JSONUtils { std::pair fileSegmentationEngineJSONEachRow(ReadBuffer & in, DB::Memory<> & memory, size_t min_bytes, size_t max_rows); @@ -136,6 +145,106 @@ namespace JSONUtils bool skipUntilFieldInObject(ReadBuffer & in, const String & desired_field_name, const FormatSettings::JSON & settings); void skipTheRestOfObject(ReadBuffer & in, const FormatSettings::JSON & settings); + + template + ReturnType deserializeEmpyStringAsDefaultOrNested(IColumn & column, ReadBuffer & istr, const FormatSettings & settings, auto && deserializer) + { + static constexpr auto throw_exception = std::is_same_v; + + static constexpr auto EMPTY_STRING = "\"\""; + static constexpr auto EMPTY_STRING_LENGTH = std::string_view(EMPTY_STRING).length(); + + auto do_deserialize_nested = [](IColumn & nested_column, ReadBuffer & buf, auto && check_for_empty_string, auto && deserialize, const SerializationPtr & nested_column_serialization) -> ReturnType + { + if (check_for_empty_string(buf)) + { + nested_column.insertDefault(); + return ReturnType(true); + } + return deserialize(nested_column, buf, nested_column_serialization); + }; + + auto deserialize_nested_impl = [&settings](IColumn & nested_column, ReadBuffer & buf, const SerializationPtr & nested_column_serialization) -> ReturnType + { + if constexpr (throw_exception) + { + if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(nested_column)) + SerializationNullable::deserializeNullAsDefaultOrNestedTextJSON(nested_column, buf, settings, nested_column_serialization); + else + nested_column_serialization->deserializeTextJSON(nested_column, buf, settings); + } + else + { + if (settings.null_as_default && !isColumnNullableOrLowCardinalityNullable(nested_column)) + return SerializationNullable::tryDeserializeNullAsDefaultOrNestedTextJSON(nested_column, buf, settings, nested_column_serialization); + return nested_column_serialization->tryDeserializeTextJSON(nested_column, buf, settings); + } + }; + + auto deserialize_nested = [&settings, &do_deserialize_nested, &deserialize_nested_impl](IColumn & nested_column, ReadBuffer & buf, const SerializationPtr & nested_column_serialization) -> ReturnType + { + if (!settings.json.empty_as_default || buf.eof() || *buf.position() != EMPTY_STRING[0]) + return deserialize_nested_impl(nested_column, buf, nested_column_serialization); + + if (buf.available() >= EMPTY_STRING_LENGTH) + { + /// We have enough data in buffer to check if we have an empty string. + auto check_for_empty_string = [](ReadBuffer & buf_) -> bool + { + auto * pos = buf_.position(); + if (checkString(EMPTY_STRING, buf_)) + return true; + buf_.position() = pos; + return false; + }; + + return do_deserialize_nested(nested_column, buf, check_for_empty_string, deserialize_nested_impl, nested_column_serialization); + } + + /// We don't have enough data in buffer to check if we have an empty string. + /// Use PeekableReadBuffer to make a checkpoint before checking for an + /// empty string and rollback if check was failed. + + auto check_for_empty_string = [](ReadBuffer & buf_) -> bool + { + auto & peekable_buf = assert_cast(buf_); + peekable_buf.setCheckpoint(); + SCOPE_EXIT(peekable_buf.dropCheckpoint()); + if (checkString(EMPTY_STRING, peekable_buf)) + return true; + peekable_buf.rollbackToCheckpoint(); + return false; + }; + + auto deserialize_nested_impl_with_check = [&deserialize_nested_impl](IColumn & nested_column_, ReadBuffer & buf_, const SerializationPtr & nested_column_serialization_) -> ReturnType + { + auto & peekable_buf = assert_cast(buf_); + + auto enforceNoUnreadData = [&peekable_buf]() -> void + { + if (unlikely(peekable_buf.hasUnreadData())) + throw Exception(ErrorCodes::LOGICAL_ERROR, "Incorrect state while parsing JSON: PeekableReadBuffer has unread data in own memory: {}", String(peekable_buf.position(), peekable_buf.available())); + }; + + if constexpr (throw_exception) + { + deserialize_nested_impl(nested_column_, peekable_buf, nested_column_serialization_); + enforceNoUnreadData(); + } + else + { + bool res = deserialize_nested_impl(nested_column_, peekable_buf, nested_column_serialization_); + enforceNoUnreadData(); + return res; + } + }; + + PeekableReadBuffer peekable_buf(buf, true); + return do_deserialize_nested(nested_column, peekable_buf, check_for_empty_string, deserialize_nested_impl_with_check, nested_column_serialization); + }; + + return deserializer(column, istr, deserialize_nested); + } } }