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..1eaaf64e 100644 --- a/ut/columns_ut.cpp +++ b/ut/columns_ut.cpp @@ -184,6 +184,60 @@ 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, 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());