Skip to content

Tests for Column::GetItem #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions clickhouse/columns/date.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void ColumnDate::Swap(Column& other) {
}

ItemView ColumnDate::GetItem(size_t index) const {
return data_->GetItem(index);
return ItemView(Type::Date, data_->GetItem(index));
}


Expand Down Expand Up @@ -128,7 +128,7 @@ void ColumnDateTime::Swap(Column& other) {
}

ItemView ColumnDateTime::GetItem(size_t index) const {
return data_->GetItem(index);
return ItemView(Type::DateTime, data_->GetItem(index));
}

ColumnDateTime64::ColumnDateTime64(size_t precision)
Expand Down Expand Up @@ -186,7 +186,7 @@ size_t ColumnDateTime64::Size() const {
}

ItemView ColumnDateTime64::GetItem(size_t index) const {
return data_->GetItem(index);
return ItemView(Type::DateTime64, data_->GetItem(index));
}

void ColumnDateTime64::Swap(Column& other) {
Expand Down
2 changes: 1 addition & 1 deletion clickhouse/columns/decimal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ void ColumnDecimal::Swap(Column& other) {
}

ItemView ColumnDecimal::GetItem(size_t index) const {
return data_->GetItem(index);
return ItemView{GetType().GetCode(), data_->GetItem(index)};
}

size_t ColumnDecimal::GetScale() const
Expand Down
2 changes: 1 addition & 1 deletion clickhouse/columns/ip4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void ColumnIPv4::Swap(Column& other) {
}

ItemView ColumnIPv4::GetItem(size_t index) const {
return data_->GetItem(index);
return ItemView(Type::IPv4, data_->GetItem(index));
}

}
2 changes: 1 addition & 1 deletion clickhouse/columns/ip6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void ColumnIPv6::Swap(Column& other) {
}

ItemView ColumnIPv6::GetItem(size_t index) const {
return data_->GetItem(index);
return ItemView{Type::IPv6, data_->GetItem(index)};
}

}
68 changes: 46 additions & 22 deletions clickhouse/columns/itemview.cpp
Original file line number Diff line number Diff line change
@@ -1,44 +1,71 @@
#include "../columns/itemview.h"

#include <algorithm>
#include <sstream>

namespace {

template <typename Container>
std::string ContainerToString(Container container, const char * separator = ", ") {
std::stringstream sstr;
const auto end = std::end(container);
for (auto i = std::begin(container); i != end; /*intentionally no ++i*/) {
const auto & elem = *i;
sstr << elem;

if (++i != end) {
sstr << separator;
}
}

return sstr.str();
}

}

namespace clickhouse {

void ItemView::ValidateData(Type::Code type, DataType data) {
int expected_size = 0;

auto AssertSize = [type, &data](std::initializer_list<int> allowed_sizes) -> void {
const auto end = std::end(allowed_sizes);
if (std::find(std::begin(allowed_sizes), end, static_cast<int>(data.size())) == end) {
throw AssertionError(std::string("ItemView value size mismatch for ")
+ Type::TypeName(type)
+ " expected: " + ContainerToString(allowed_sizes, " or ")
+ ", got: " + std::to_string(data.size()));
}
};

switch (type) {
case Type::Code::Void:
expected_size = 0;
break;
return AssertSize({0});

case Type::Code::Int8:
case Type::Code::UInt8:
case Type::Code::Enum8:
expected_size = 1;
break;
return AssertSize({1});

case Type::Code::Int16:
case Type::Code::UInt16:
case Type::Code::Date:
case Type::Code::Enum16:
expected_size = 2;
break;
return AssertSize({2});

case Type::Code::Int32:
case Type::Code::UInt32:
case Type::Code::Float32:
case Type::Code::DateTime:
case Type::Code::IPv4:
case Type::Code::Decimal32:
expected_size = 4;
break;
return AssertSize({4});

case Type::Code::Int64:
case Type::Code::UInt64:
case Type::Code::Float64:
case Type::Code::DateTime64:
case Type::Code::IPv6:
case Type::Code::Decimal64:
expected_size = 8;
break;
return AssertSize({8});

case Type::Code::String:
case Type::Code::FixedString:
Expand All @@ -49,24 +76,21 @@ void ItemView::ValidateData(Type::Code type, DataType data) {
case Type::Code::Nullable:
case Type::Code::Tuple:
case Type::Code::LowCardinality:
throw UnimplementedError("Unsupported type in ItemView: " + std::to_string(static_cast<int>(type)));
throw AssertionError("Unsupported type in ItemView: " + std::string(Type::TypeName(type)));

case Type::Code::IPv6:
case Type::Code::UUID:
case Type::Code::Int128:
case Type::Code::Decimal:
case Type::Code::Decimal128:
expected_size = 16;
break;
return AssertSize({16});

case Type::Code::Decimal:
// Could be either Decimal32, Decimal64 or Decimal128
return AssertSize({4, 8, 16});

default:
throw UnimplementedError("Unknon type code:" + std::to_string(static_cast<int>(type)));
}

if (expected_size != static_cast<int>(data.size())) {
throw AssertionError("Value size mismatch for type "
+ std::to_string(static_cast<int>(type)) + " expected: "
+ std::to_string(expected_size) + ", got: " + std::to_string(data.size()));
}
}

}
19 changes: 14 additions & 5 deletions clickhouse/columns/itemview.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <string_view>
#include <stdexcept>
#include <type_traits>

namespace clickhouse {

Expand Down Expand Up @@ -43,8 +44,15 @@ struct ItemView {
ValidateData(type, data);
}

ItemView(Type::Code type, ItemView other)
: type(type),
data(other.data)
{
ValidateData(type, data);
}

explicit ItemView()
: ItemView(Type::Void, {})
: ItemView(Type::Void, std::string_view{})
{}

template <typename T>
Expand All @@ -53,11 +61,12 @@ struct ItemView {
{}

template <typename T>
T get() const {
if constexpr (std::is_same_v<std::string_view, T> || std::is_same_v<std::string, T>) {
auto get() const {
using ValueType = std::remove_cv_t<std::decay_t<T>>;
if constexpr (std::is_same_v<std::string_view, ValueType> || std::is_same_v<std::string, ValueType>) {
return data;
} else if constexpr (std::is_fundamental_v<T> || std::is_same_v<Int128, T>) {
if (sizeof(T) == data.size()) {
} else if constexpr (std::is_fundamental_v<ValueType> || std::is_same_v<Int128, ValueType>) {
if (sizeof(ValueType) == data.size()) {
return *reinterpret_cast<const T*>(data.data());
} else {
throw AssertionError("Incompatitable value type and size.");
Expand Down
6 changes: 5 additions & 1 deletion clickhouse/columns/uuid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ void ColumnUUID::Swap(Column& other) {
}

ItemView ColumnUUID::GetItem(size_t index) const {
return data_->GetItem(index);
// We know that ColumnUInt64 stores it's data in continius memory region,
// and that every 2 values from data represent 1 UUID value.
const auto data_item_view = data_->GetItem(index * 2);

return ItemView{Type::UUID, std::string_view{data_item_view.data.data(), data_item_view.data.size() * 2}};
}

}
Expand Down
63 changes: 41 additions & 22 deletions clickhouse/types/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,69 @@ Type::Type(const Code code)
, type_unique_id_(0)
{}

const char* Type::TypeName(Type::Code code) {
switch (code) {
case Type::Code::Void: return "Void";
case Type::Code::Int8: return "Int8";
case Type::Code::Int16: return "Int16";
case Type::Code::Int32: return "Int32";
case Type::Code::Int64: return "Int64";
case Type::Code::UInt8: return "UInt8";
case Type::Code::UInt16: return "UInt16";
case Type::Code::UInt32: return "UInt32";
case Type::Code::UInt64: return "UInt64";
case Type::Code::Float32: return "Float32";
case Type::Code::Float64: return "Float64";
case Type::Code::String: return "String";
case Type::Code::FixedString: return "FixedString";
case Type::Code::DateTime: return "DateTime";
case Type::Code::Date: return "Date";
case Type::Code::Array: return "Array";
case Type::Code::Nullable: return "Nullable";
case Type::Code::Tuple: return "Tuple";
case Type::Code::Enum8: return "Enum8";
case Type::Code::Enum16: return "Enum16";
case Type::Code::UUID: return "UUID";
case Type::Code::IPv4: return "IPv4";
case Type::Code::IPv6: return "IPv6";
case Type::Code::Int128: return "Int128";
case Type::Code::Decimal: return "Decimal";
case Type::Code::Decimal32: return "Decimal32";
case Type::Code::Decimal64: return "Decimal64";
case Type::Code::Decimal128: return "Decimal128";
case Type::Code::LowCardinality: return "LowCardinality";
case Type::Code::DateTime64: return "DateTime64";
}

return "Unknown type";
}

std::string Type::GetName() const {
switch (code_) {
case Void:
return "Void";
case Int8:
return "Int8";
case Int16:
return "Int16";
case Int32:
return "Int32";
case Int64:
return "Int64";
case Int128:
return "Int128";
case UInt8:
return "UInt8";
case UInt16:
return "UInt16";
case UInt32:
return "UInt32";
case UInt64:
return "UInt64";
case UUID:
return "UUID";
case Float32:
return "Float32";
case Float64:
return "Float64";
case String:
return "String";
case FixedString:
return As<FixedStringType>()->GetName();
case IPv4:
return "IPv4";
case IPv6:
return "IPv6";
case Date:
return TypeName(code_);
case FixedString:
return As<FixedStringType>()->GetName();
case DateTime:
{
return As<DateTimeType>()->GetName();
}
case DateTime64:
return As<DateTime64Type>()->GetName();
case Date:
return "Date";
case Array:
return As<ArrayType>()->GetName();
case Nullable:
Expand Down
3 changes: 3 additions & 0 deletions clickhouse/types/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ class Type {

bool IsEqual(const TypeRef& other) const { return IsEqual(*other); }

/// Simple name, doesn't depend on parameters and\or nested types, caller MUST NOT free returned value.
static const char* TypeName(Code);

public:
static TypeRef CreateArray(TypeRef item_type);

Expand Down
39 changes: 39 additions & 0 deletions ut/Column_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,45 @@ TYPED_TEST(GenericColumnTest, Append) {
EXPECT_TRUE(CompareRecursive(values, *column));
}

// To make some value types compatitable with Column::GetItem()
template <typename ColumnType, typename ValueType>
inline auto convertValueForGetItem(const ColumnType& col, ValueType&& t) {
using T = std::remove_cv_t<std::decay_t<ValueType>>;

if constexpr (std::is_same_v<ColumnType, ColumnDecimal>) {
// 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<const char*>(&t), item.data.size());
} else if constexpr (std::is_same_v<T, clickhouse::UInt128>
|| std::is_same_v<T, clickhouse::Int128>) {
return std::string_view{reinterpret_cast<const char*>(&t), sizeof(T)};
} else if constexpr (std::is_same_v<T, in_addr>) {
return htonl(t.s_addr);
} else if constexpr (std::is_same_v<T, in6_addr>) {
return std::string_view(reinterpret_cast<const char*>(t.s6_addr), 16);
} else if constexpr (std::is_same_v<ColumnType, ColumnDate>) {
return static_cast<uint16_t>(t / std::time_t(86400));
} else if constexpr (std::is_same_v<ColumnType, ColumnDateTime>) {
return static_cast<uint32_t>(t);
} else {
return t;
}
}

TYPED_TEST(GenericColumnTest, GetItem) {
auto [column, values] = this->MakeColumnWithValues(100);

ASSERT_EQ(values.size(), column->Size());
ASSERT_EQ(column->GetItem(0).type, column->GetType().GetCode());

for (size_t i = 0; i < values.size(); ++i) {
const auto v = convertValueForGetItem(*column, values[i]);
const ItemView item = column->GetItem(i);

ASSERT_TRUE(CompareRecursive(item.get<decltype(v)>(), v));
}
}

TYPED_TEST(GenericColumnTest, Slice) {
auto [column, values] = this->MakeColumnWithValues(100);

Expand Down
Loading