diff --git a/README.md b/README.md index cec69b0f..dda91164 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ C++ client for [ClickHouse](https://clickhouse.com/). * LowCardinality(String) or LowCardinality(FixedString(N)) * Tuple * UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64 -* Int128 +* UInt128, Int128 * UUID * Map * Point, Ring, Polygon, MultiPolygon diff --git a/clickhouse/base/uuid.h b/clickhouse/base/uuid.h index d78a1866..87db5ec9 100644 --- a/clickhouse/base/uuid.h +++ b/clickhouse/base/uuid.h @@ -5,8 +5,6 @@ namespace clickhouse { -using UInt128 = std::pair; - -using UUID = UInt128; +using UUID = std::pair; } diff --git a/clickhouse/columns/factory.cpp b/clickhouse/columns/factory.cpp index aeacdabc..73f2cde1 100644 --- a/clickhouse/columns/factory.cpp +++ b/clickhouse/columns/factory.cpp @@ -67,6 +67,8 @@ static ColumnRef CreateTerminalColumn(const TypeAst& ast) { return std::make_shared(); case Type::Int128: return std::make_shared(); + case Type::UInt128: + return std::make_shared(); case Type::Float32: return std::make_shared(); diff --git a/clickhouse/columns/itemview.cpp b/clickhouse/columns/itemview.cpp index 12c89c31..c92627d2 100644 --- a/clickhouse/columns/itemview.cpp +++ b/clickhouse/columns/itemview.cpp @@ -82,6 +82,7 @@ void ItemView::ValidateData(Type::Code type, DataType data) { case Type::Code::IPv6: case Type::Code::UUID: + case Type::Code::UInt128: case Type::Code::Int128: case Type::Code::Decimal128: return AssertSize({16}); diff --git a/clickhouse/columns/itemview.h b/clickhouse/columns/itemview.h index ae48a362..71f20355 100644 --- a/clickhouse/columns/itemview.h +++ b/clickhouse/columns/itemview.h @@ -28,7 +28,7 @@ struct ItemView { inline auto ConvertToStorageValue(const T& t) { if constexpr (std::is_same_v || std::is_same_v) { return std::string_view{t}; - } else if constexpr (std::is_fundamental_v || std::is_same_v>) { + } else if constexpr (std::is_fundamental_v || std::is_same_v> || std::is_same_v>) { return std::string_view{reinterpret_cast(&t), sizeof(T)}; } else { static_assert(!std::is_same_v, "Unknown type, which can't be stored in ItemView"); diff --git a/clickhouse/columns/numeric.cpp b/clickhouse/columns/numeric.cpp index 1c611c79..4819f37a 100644 --- a/clickhouse/columns/numeric.cpp +++ b/clickhouse/columns/numeric.cpp @@ -118,6 +118,7 @@ template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; +template class ColumnVector; template class ColumnVector; template class ColumnVector; diff --git a/clickhouse/columns/numeric.h b/clickhouse/columns/numeric.h index e2a7675e..5187b727 100644 --- a/clickhouse/columns/numeric.h +++ b/clickhouse/columns/numeric.h @@ -67,12 +67,14 @@ class ColumnVector : public Column { }; using Int128 = absl::int128; +using UInt128 = absl::uint128; using Int64 = int64_t; using ColumnUInt8 = ColumnVector; using ColumnUInt16 = ColumnVector; using ColumnUInt32 = ColumnVector; using ColumnUInt64 = ColumnVector; +using ColumnUInt128 = ColumnVector; using ColumnInt8 = ColumnVector; using ColumnInt16 = ColumnVector; diff --git a/clickhouse/types/type_parser.cpp b/clickhouse/types/type_parser.cpp index 6142dec2..52058e80 100644 --- a/clickhouse/types/type_parser.cpp +++ b/clickhouse/types/type_parser.cpp @@ -54,7 +54,7 @@ static const std::unordered_map kTypeCode = { { "IPv4", Type::IPv4 }, { "IPv6", Type::IPv6 }, { "Int128", Type::Int128 }, -// { "UInt128", Type::UInt128 }, + { "UInt128", Type::UInt128 }, { "Decimal", Type::Decimal }, { "Decimal32", Type::Decimal32 }, { "Decimal64", Type::Decimal64 }, diff --git a/clickhouse/types/types.cpp b/clickhouse/types/types.cpp index e1084fb0..c14c86c5 100644 --- a/clickhouse/types/types.cpp +++ b/clickhouse/types/types.cpp @@ -39,6 +39,7 @@ const char* Type::TypeName(Type::Code code) { case Type::Code::IPv4: return "IPv4"; case Type::Code::IPv6: return "IPv6"; case Type::Code::Int128: return "Int128"; + case Type::Code::UInt128: return "UInt128"; case Type::Code::Decimal: return "Decimal"; case Type::Code::Decimal32: return "Decimal32"; case Type::Code::Decimal64: return "Decimal64"; @@ -68,6 +69,7 @@ std::string Type::GetName() const { case UInt16: case UInt32: case UInt64: + case UInt128: case UUID: case Float32: case Float64: @@ -126,6 +128,7 @@ uint64_t Type::GetTypeUniqueId() const { case UInt16: case UInt32: case UInt64: + case UInt128: case UUID: case Float32: case Float64: diff --git a/clickhouse/types/types.h b/clickhouse/types/types.h index 12e2cbd5..71613323 100644 --- a/clickhouse/types/types.h +++ b/clickhouse/types/types.h @@ -12,6 +12,7 @@ namespace clickhouse { using Int128 = absl::int128; +using UInt128 = absl::uint128; using Int64 = int64_t; using TypeRef = std::shared_ptr; @@ -43,6 +44,7 @@ class Type { IPv4, IPv6, Int128, + UInt128, Decimal, Decimal32, Decimal64, @@ -339,6 +341,11 @@ inline TypeRef Type::CreateSimple() { return TypeRef(new Type(Int128)); } +template <> +inline TypeRef Type::CreateSimple() { + return TypeRef(new Type(UInt128)); +} + template <> inline TypeRef Type::CreateSimple() { return TypeRef(new Type(UInt8)); diff --git a/ut/Column_ut.cpp b/ut/Column_ut.cpp index d946e7dc..04cb5d78 100644 --- a/ut/Column_ut.cpp +++ b/ut/Column_ut.cpp @@ -207,6 +207,7 @@ using TestCases = ::testing::Types< GenericColumnTestCase, in6_addr, &MakeIPv6s>, GenericColumnTestCase, clickhouse::Int128, &MakeInt128s>, + GenericColumnTestCase, clickhouse::UInt128, &MakeUInt128s>, GenericColumnTestCase, clickhouse::UUID, &MakeUUIDs>, DecimalColumnTestCase, @@ -286,7 +287,7 @@ inline auto convertValueForGetItem(const ColumnType& col, ValueType&& t) { // Since ColumnDecimal can hold 32, 64, 128-bit wide data and there is no way telling at run-time. const ItemView item = col.GetItem(0); return std::string_view(reinterpret_cast(&t), item.data.size()); - } else if constexpr (std::is_same_v + } else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) { return std::string_view{reinterpret_cast(&t), sizeof(T)}; } else if constexpr (std::is_same_v) { diff --git a/ut/CreateColumnByType_ut.cpp b/ut/CreateColumnByType_ut.cpp index b6794275..556dfc36 100644 --- a/ut/CreateColumnByType_ut.cpp +++ b/ut/CreateColumnByType_ut.cpp @@ -76,7 +76,7 @@ INSTANTIATE_TEST_SUITE_P(Basic, CreateColumnByTypeWithName, ::testing::Values( "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "String", "Date", "DateTime", - "UUID", "Int128" + "UUID", "Int128", "UInt128" )); INSTANTIATE_TEST_SUITE_P(Parametrized, CreateColumnByTypeWithName, ::testing::Values( diff --git a/ut/columns_ut.cpp b/ut/columns_ut.cpp index 623fdf0e..314cabdf 100644 --- a/ut/columns_ut.cpp +++ b/ut/columns_ut.cpp @@ -483,6 +483,28 @@ TEST(ColumnsCase, Int128) { EXPECT_EQ(0, col->At(4)); } +TEST(ColumnsCase, UInt128) { + auto col = std::make_shared(std::vector{ + absl::MakeUint128(0xffffffffffffffffll, 0xffffffffffffffffll), // 2^128 - 1 + absl::MakeUint128(0, 0xffffffffffffffffll), // 2^64 - 1 + absl::MakeUint128(0xffffffffffffffffll, 0), // 2^128 - 2^64 + absl::MakeUint128(0x8000000000000000ll, 0), + UInt128(0) + }); + + EXPECT_EQ(absl::MakeUint128(0xffffffffffffffffll, 0xffffffffffffffffll), col->At(0)); + + EXPECT_EQ(absl::MakeUint128(0, 0xffffffffffffffffll), col->At(1)); + EXPECT_EQ(0ull, absl::Uint128High64(col->At(1))); + EXPECT_EQ(0xffffffffffffffffull, absl::Uint128Low64(col->At(1))); + + EXPECT_EQ(absl::MakeUint128(0xffffffffffffffffll, 0), col->At(2)); + EXPECT_EQ(static_cast(0xffffffffffffffffull), absl::Uint128High64(col->At(2))); + EXPECT_EQ(0ull, absl::Uint128Low64(col->At(2))); + + EXPECT_EQ(0, col->At(4)); +} + TEST(ColumnsCase, ColumnIPv4) { // TODO: split into proper method-level unit-tests diff --git a/ut/value_generators.cpp b/ut/value_generators.cpp index f6d7baf9..5504fd1d 100644 --- a/ut/value_generators.cpp +++ b/ut/value_generators.cpp @@ -104,13 +104,23 @@ std::vector MakeDateTimes() { std::vector MakeInt128s() { return { absl::MakeInt128(0xffffffffffffffffll, 0xffffffffffffffffll), // -1 - absl::MakeInt128(0, 0xffffffffffffffffll), // 2^64 + absl::MakeInt128(0, 0xffffffffffffffffll), // 2^64 - 1 absl::MakeInt128(0xffffffffffffffffll, 0), absl::MakeInt128(0x8000000000000000ll, 0), Int128(0) }; } +std::vector MakeUInt128s() { + return { + absl::MakeUint128(0xffffffffffffffffll, 0xffffffffffffffffll), // 2^128 - 1 + absl::MakeUint128(0, 0xffffffffffffffffll), // 2^64 - 1 + absl::MakeUint128(0xffffffffffffffffll, 0), // 2^128 - 2^64 + absl::MakeUint128(0x8000000000000000ll, 0), + UInt128(0) + }; +} + std::vector MakeDecimals(size_t /*precision*/, size_t scale) { const auto scale_multiplier = static_cast(std::pow(10, scale)); const long long int rhs_value = 12345678910; diff --git a/ut/value_generators.h b/ut/value_generators.h index 031f0fe9..f0bae267 100644 --- a/ut/value_generators.h +++ b/ut/value_generators.h @@ -39,6 +39,7 @@ std::vector MakeIPv4s(); std::vector MakeIPv6s(); std::vector MakeUUIDs(); std::vector MakeInt128s(); +std::vector MakeUInt128s(); std::vector MakeDecimals(size_t precision, size_t scale); template ::value, bool> = true>