From f11e78a285dd14d11a98674cca226b6583d14f08 Mon Sep 17 00:00:00 2001 From: Andrew Slabko Date: Wed, 8 Jul 2026 16:39:15 +0200 Subject: [PATCH] Restore NullableT append exception safety --- clickhouse/columns/json.h | 13 +++++++++---- clickhouse/columns/nullable.h | 13 +++++++++---- ut/Column_ut.cpp | 12 +++++++++++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/clickhouse/columns/json.h b/clickhouse/columns/json.h index bc9a1ede..f554b08d 100644 --- a/clickhouse/columns/json.h +++ b/clickhouse/columns/json.h @@ -72,10 +72,15 @@ class ColumnJSON : public Column { template <> inline void ColumnNullableT::Append(std::optional value) { ColumnNullable::Append(!value.has_value()); - if (value.has_value()) { - typed_nested_data_->Append(*value); - } else { - typed_nested_data_->Append(std::string_view("{}")); + try { + if (value.has_value()) { + typed_nested_data_->Append(*value); + } else { + typed_nested_data_->Append(std::string_view("{}")); + } + } catch (...) { + Nulls()->AsStrict()->Erase(Size() - 1); + throw; } } diff --git a/clickhouse/columns/nullable.h b/clickhouse/columns/nullable.h index 1946e8b9..6b34552c 100644 --- a/clickhouse/columns/nullable.h +++ b/clickhouse/columns/nullable.h @@ -96,10 +96,15 @@ class ColumnNullableT : public ColumnNullable { inline void Append(ValueType value) { ColumnNullable::Append(!value.has_value()); - if (value.has_value()) { - typed_nested_data_->Append(std::move(*value)); - } else { - typed_nested_data_->Append(typename ValueType::value_type{}); + try { + if (value.has_value()) { + typed_nested_data_->Append(std::move(*value)); + } else { + typed_nested_data_->Append(typename ValueType::value_type{}); + } + } catch (...) { + Nulls()->template As()->Erase(Size() - 1); + throw; } } diff --git a/ut/Column_ut.cpp b/ut/Column_ut.cpp index c0fdc1ac..df16e170 100644 --- a/ut/Column_ut.cpp +++ b/ut/Column_ut.cpp @@ -41,6 +41,17 @@ std::ostream& operator<<(std::ostream& ostr, const Type::Code& type_code) { } +TEST(ColumnNullableT, AppendRollsBackNullFlagWhenNestedAppendThrows) { + auto nested = std::make_shared(1); + auto column = std::make_shared>(nested); + + EXPECT_THROW(column->Append(std::string_view("too long")), ValidationError); + + EXPECT_EQ(0u, column->Size()); + EXPECT_EQ(0u, column->Nulls()->Size()); + EXPECT_EQ(0u, column->Nested()->Size()); +} + // Generic tests for a Column subclass against basic API: // 1. Constructor: Create, ensure that it is empty @@ -515,4 +526,3 @@ TYPED_TEST(GenericColumnTest, ArrayT_RoundTrip) { this->TestColumnRoundtrip(column, LocalHostEndpoint, AllCompressionMethods); } -