From e921d4ea32cc7224f8898b76f7576652188e97cb Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 24 Aug 2026 15:04:02 +0200 Subject: [PATCH 1/2] Validate Decimal parameters before swapping --- clickhouse/columns/decimal.cpp | 13 +++++++++++ ut/columns_ut.cpp | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/clickhouse/columns/decimal.cpp b/clickhouse/columns/decimal.cpp index 30c4f9f1..cda00a71 100644 --- a/clickhouse/columns/decimal.cpp +++ b/clickhouse/columns/decimal.cpp @@ -236,6 +236,19 @@ ColumnRef ColumnDecimal::CloneEmpty() const { void ColumnDecimal::Swap(Column& other) { auto & col = dynamic_cast(other); + + if (col.GetPrecision() != GetPrecision()) { + throw ValidationError("Can't swap Decimal columns when precisions are not the same: " + + std::to_string(GetPrecision()) + "(this) != " + + std::to_string(col.GetPrecision()) + "(that)"); + } + + if (col.GetScale() != GetScale()) { + throw ValidationError("Can't swap Decimal columns when scales are not the same: " + + std::to_string(GetScale()) + "(this) != " + + std::to_string(col.GetScale()) + "(that)"); + } + data_.swap(col.data_); } diff --git a/ut/columns_ut.cpp b/ut/columns_ut.cpp index 8421b5d2..d1b30bba 100644 --- a/ut/columns_ut.cpp +++ b/ut/columns_ut.cpp @@ -184,6 +184,46 @@ TEST(ColumnsCase, DecimalStringAt) { } +TEST(ColumnsCase, DecimalSwap) { + auto column1 = std::make_shared(18, 2); + auto column2 = std::make_shared(18, 2); + column1->Append("1.23"); + column2->Append("4.56"); + + column1->Swap(*column2); + + EXPECT_EQ(column1->StringAt(0), "4.56"); + EXPECT_EQ(column2->StringAt(0), "1.23"); +} + +TEST(ColumnsCase, DecimalSwapDifferentScale) { + auto column1 = std::make_shared(18, 2); + auto column2 = std::make_shared(18, 3); + column1->Append("1.23"); + column2->Append("4.567"); + + EXPECT_THROW(column1->Swap(*column2), ValidationError); + + EXPECT_EQ(column1->GetType().GetName(), "Decimal(18,2)"); + EXPECT_EQ(column2->GetType().GetName(), "Decimal(18,3)"); + EXPECT_EQ(column1->StringAt(0), "1.23"); + EXPECT_EQ(column2->StringAt(0), "4.567"); +} + +TEST(ColumnsCase, DecimalSwapDifferentPrecision) { + auto column1 = std::make_shared(9, 2); + auto column2 = std::make_shared(18, 2); + column1->Append("1.23"); + column2->Append("4.56"); + + EXPECT_THROW(column1->Swap(*column2), ValidationError); + + EXPECT_EQ(column1->GetType().GetName(), "Decimal(9,2)"); + EXPECT_EQ(column2->GetType().GetName(), "Decimal(18,2)"); + EXPECT_EQ(column1->StringAt(0), "1.23"); + EXPECT_EQ(column2->StringAt(0), "4.56"); +} + TEST(ColumnsCase, NumericInit) { auto col = std::make_shared(MakeNumbers()); From 7dc75acd33e9a2b183b5e2b628ef8f09b341945b Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 24 Aug 2026 15:23:49 +0200 Subject: [PATCH 2/2] Test Decimal precision mismatch with same storage type --- ut/columns_ut.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ut/columns_ut.cpp b/ut/columns_ut.cpp index d1b30bba..1eaaf64e 100644 --- a/ut/columns_ut.cpp +++ b/ut/columns_ut.cpp @@ -224,6 +224,20 @@ TEST(ColumnsCase, DecimalSwapDifferentPrecision) { EXPECT_EQ(column2->StringAt(0), "4.56"); } +TEST(ColumnsCase, DecimalSwapDifferentPrecisionSameStorageType) { + auto column1 = std::make_shared(17, 2); + auto column2 = std::make_shared(18, 2); + column1->Append("1.23"); + column2->Append("4.56"); + + EXPECT_THROW(column1->Swap(*column2), ValidationError); + + EXPECT_EQ(column1->GetType().GetName(), "Decimal(17,2)"); + EXPECT_EQ(column2->GetType().GetName(), "Decimal(18,2)"); + EXPECT_EQ(column1->StringAt(0), "1.23"); + EXPECT_EQ(column2->StringAt(0), "4.56"); +} + TEST(ColumnsCase, NumericInit) { auto col = std::make_shared(MakeNumbers());