Skip to content

Commit

Permalink
Merge pull request #258 from den818/Geo
Browse files Browse the repository at this point in the history
Support geo column types
  • Loading branch information
Enmk authored Dec 16, 2022
2 parents 0472da2 + bac2967 commit 4251535
Show file tree
Hide file tree
Showing 13 changed files with 371 additions and 17 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ C++ client for [ClickHouse](https://clickhouse.com/).
* Int128
* UUID
* Map
* Point, Ring, Polygon, MultiPolygon

## Building

Expand Down
2 changes: 2 additions & 0 deletions clickhouse/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ SET ( clickhouse-cpp-lib-src
columns/decimal.cpp
columns/enum.cpp
columns/factory.cpp
columns/geo.cpp
columns/ip4.cpp
columns/ip6.cpp
columns/lowcardinality.cpp
Expand Down Expand Up @@ -117,6 +118,7 @@ INSTALL(FILES columns/date.h DESTINATION include/clickhouse/columns/)
INSTALL(FILES columns/decimal.h DESTINATION include/clickhouse/columns/)
INSTALL(FILES columns/enum.h DESTINATION include/clickhouse/columns/)
INSTALL(FILES columns/factory.h DESTINATION include/clickhouse/columns/)
INSTALL(FILES columns/geo.h DESTINATION include/clickhouse/columns/)
INSTALL(FILES columns/ip4.h DESTINATION include/clickhouse/columns/)
INSTALL(FILES columns/ip6.h DESTINATION include/clickhouse/columns/)
INSTALL(FILES columns/itemview.h DESTINATION include/clickhouse/columns/)
Expand Down
1 change: 1 addition & 0 deletions clickhouse/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "columns/date.h"
#include "columns/decimal.h"
#include "columns/enum.h"
#include "columns/geo.h"
#include "columns/ip4.h"
#include "columns/ip6.h"
#include "columns/lowcardinality.h"
Expand Down
16 changes: 15 additions & 1 deletion clickhouse/columns/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
#include "date.h"
#include "decimal.h"
#include "enum.h"
#include "geo.h"
#include "ip4.h"
#include "ip6.h"
#include "lowcardinality.h"
#include "lowcardinalityadaptor.h"
#include "map.h"
#include "nothing.h"
#include "nullable.h"
#include "numeric.h"
#include "string.h"
#include "tuple.h"
#include "uuid.h"
#include "map.h"


#include "../types/type_parser.h"

Expand Down Expand Up @@ -97,6 +99,18 @@ static ColumnRef CreateTerminalColumn(const TypeAst& ast) {
case Type::UUID:
return std::make_shared<ColumnUUID>();

case Type::Point:
return std::make_shared<ColumnPoint>();

case Type::Ring:
return std::make_shared<ColumnRing>();

case Type::Polygon:
return std::make_shared<ColumnPolygon>();

case Type::MultiPolygon:
return std::make_shared<ColumnMultiPolygon>();

default:
return nullptr;
}
Expand Down
108 changes: 108 additions & 0 deletions clickhouse/columns/geo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "geo.h"

#include "utils.h"

namespace {
using namespace ::clickhouse;

template <Type::Code type_code>
TypeRef CreateGeoType() {
if constexpr (type_code == Type::Code::Point) {
return Type::CreatePoint();
} else if constexpr (type_code == Type::Code::Ring) {
return Type::CreateRing();
} else if constexpr (type_code == Type::Code::Polygon) {
return Type::CreatePolygon();
} else if constexpr (type_code == Type::Code::MultiPolygon) {
return Type::CreateMultiPolygon();
}
}

template <typename ColumnType>
std::shared_ptr<ColumnType> CreateColumn() {
if constexpr (std::is_same_v<ColumnType, ColumnTupleT<ColumnFloat64, ColumnFloat64>>) {
return std::make_shared<ColumnTupleT<ColumnFloat64, ColumnFloat64>>(
std::make_tuple(std::make_shared<ColumnFloat64>(), std::make_shared<ColumnFloat64>()));
} else {
return std::make_shared<ColumnType>();
}
}

} // namespace

namespace clickhouse {

template <typename NestedColumnType, Type::Code type_code>
ColumnGeo<NestedColumnType, type_code>::ColumnGeo()
: Column(std::move(CreateGeoType<type_code>())),
data_(std::move(CreateColumn<NestedColumnType>())) {
}

template <typename NestedColumnType, Type::Code type_code>
ColumnGeo<NestedColumnType, type_code>::ColumnGeo(ColumnRef data)
: Column(std::move(CreateGeoType<type_code>()))
, data_(std::move(WrapColumn<NestedColumnType>(std::move(data)))) {
}

template <typename NestedColumnType, Type::Code type_code>
void ColumnGeo<NestedColumnType, type_code>::Clear() {
data_->Clear();
}

template <typename NestedColumnType, Type::Code type_code>
const typename ColumnGeo<NestedColumnType, type_code>::ValueType ColumnGeo<NestedColumnType, type_code>::At(size_t n) const {
return data_->At(n);
}

template <typename NestedColumnType, Type::Code type_code>
const typename ColumnGeo<NestedColumnType, type_code>::ValueType ColumnGeo<NestedColumnType, type_code>::operator[](size_t n) const {
return data_->At(n);
}

template <typename NestedColumnType, Type::Code type_code>
void ColumnGeo<NestedColumnType, type_code>::Append(ColumnRef column) {
if (auto col = column->template As<ColumnGeo>()) {
data_->Append(col->data_->template As<Column>());
}
}

template <typename NestedColumnType, Type::Code type_code>
bool ColumnGeo<NestedColumnType, type_code>::LoadBody(InputStream* input, size_t rows) {
return data_->LoadBody(input, rows);
}

template <typename NestedColumnType, Type::Code type_code>
void ColumnGeo<NestedColumnType, type_code>::SaveBody(OutputStream* output) {
data_->SaveBody(output);
}

template <typename NestedColumnType, Type::Code type_code>
size_t ColumnGeo<NestedColumnType, type_code>::Size() const {
return data_->Size();
}

template <typename NestedColumnType, Type::Code type_code>
ColumnRef ColumnGeo<NestedColumnType, type_code>::Slice(size_t begin, size_t len) const {
return std::make_shared<ColumnGeo>(data_->Slice(begin, len));
}

template <typename NestedColumnType, Type::Code type_code>
ColumnRef ColumnGeo<NestedColumnType, type_code>::CloneEmpty() const {
return std::make_shared<ColumnGeo>();
}

template <typename NestedColumnType, Type::Code type_code>
void ColumnGeo<NestedColumnType, type_code>::Swap(Column& other) {
auto& col = dynamic_cast<ColumnGeo&>(other);
data_.swap(col.data_);
}

template class ColumnGeo<ColumnTupleT<ColumnFloat64, ColumnFloat64>, Type::Code::Point>;

template class ColumnGeo<ColumnArrayT<ColumnPoint>, Type::Code::Ring>;

template class ColumnGeo<ColumnArrayT<ColumnRing>, Type::Code::Polygon>;

template class ColumnGeo<ColumnArrayT<ColumnPolygon>, Type::Code::MultiPolygon>;

} // namespace clickhouse
76 changes: 76 additions & 0 deletions clickhouse/columns/geo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#pragma once

#include "array.h"
#include "column.h"
#include "numeric.h"
#include "tuple.h"

namespace clickhouse {

template <typename NestedColumnType, Type::Code type_code>
class ColumnGeo : public Column {
public:
using ValueType = typename NestedColumnType::ValueType;

ColumnGeo();

explicit ColumnGeo(ColumnRef data);

/// Appends one element to the end of column.
template <typename T = ValueType>
void Append(const T& value) {
data_->Append(value);
}

/// Returns element at given row number.
const ValueType At(size_t n) const;

/// Returns element at given row number.
const ValueType operator[](size_t n) const;

public:
/// Appends content of given column to the end of current one.
void Append(ColumnRef column) override;

/// Loads column data from input stream.
bool LoadBody(InputStream* input, size_t rows) override;

/// Saves column data to output stream.
void SaveBody(OutputStream* output) override;

/// Clear column data .
void Clear() override;

/// Returns count of rows in the column.
size_t Size() const override;

/// Makes slice of the current column.
ColumnRef Slice(size_t begin, size_t len) const override;
ColumnRef CloneEmpty() const override;
void Swap(Column& other) override;

private:
std::shared_ptr<NestedColumnType> data_;
};

// /**
// * Represents a Point column.
// */
using ColumnPoint = ColumnGeo<ColumnTupleT<ColumnFloat64, ColumnFloat64>, Type::Code::Point>;

/**
* Represents a Ring column.
*/
using ColumnRing = ColumnGeo<ColumnArrayT<ColumnPoint>, Type::Code::Ring>;

/**
* Represents a Polygon column.
*/
using ColumnPolygon = ColumnGeo<ColumnArrayT<ColumnRing>, Type::Code::Polygon>;

/**
* Represents a MultiPolygon column.
*/
using ColumnMultiPolygon = ColumnGeo<ColumnArrayT<ColumnPolygon>, Type::Code::MultiPolygon>;

} // namespace clickhouse
27 changes: 17 additions & 10 deletions clickhouse/columns/tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,11 @@ class ColumnTupleT : public ColumnTuple {

inline ValueType operator[](size_t index) const { return GetTupleOfValues(index); }

template <typename T, size_t index = std::tuple_size_v<T>>
inline void Append([[maybe_unused]] T value) {
static_assert(index <= std::tuple_size_v<T>);
static_assert(std::tuple_size_v<TupleOfColumns> == std::tuple_size_v<T>);
if constexpr (index == 0) {
return;
} else {
std::get<index - 1>(typed_columns_)->Append(std::move(std::get<index - 1>(value)));
Append<T, index - 1>(std::move(value));
}
using ColumnTuple::Append;

template <typename... T>
inline void Append(std::tuple<T...> value) {
AppendTuple(std::move(value));
}

/** Create a ColumnTupleT from a ColumnTuple, without copying data and offsets, but by
Expand Down Expand Up @@ -122,6 +117,18 @@ class ColumnTupleT : public ColumnTuple {
}

private:
template <typename T, size_t index = std::tuple_size_v<T>>
inline void AppendTuple([[maybe_unused]] T value) {
static_assert(index <= std::tuple_size_v<T>);
static_assert(std::tuple_size_v<TupleOfColumns> == std::tuple_size_v<T>);
if constexpr (index == 0) {
return;
} else {
std::get<index - 1>(typed_columns_)->Append(std::move(std::get<index - 1>(value)));
AppendTuple<T, index - 1>(std::move(value));
}
}

template <typename T, size_t index = std::tuple_size_v<T>>
inline static std::vector<ColumnRef> TupleToVector([[maybe_unused]] const T& value) {
static_assert(index <= std::tuple_size_v<T>);
Expand Down
6 changes: 5 additions & 1 deletion clickhouse/types/type_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ static const std::unordered_map<std::string, Type::Code> kTypeCode = {
{ "Decimal64", Type::Decimal64 },
{ "Decimal128", Type::Decimal128 },
{ "LowCardinality", Type::LowCardinality },
{ "Map", Type::Map},
{ "Map", Type::Map},
{ "Point", Type::Point},
{ "Ring", Type::Ring},
{ "Polygon", Type::Polygon},
{ "MultiPolygon", Type::MultiPolygon},
};

static Type::Code GetTypeCode(const std::string& name) {
Expand Down
28 changes: 28 additions & 0 deletions clickhouse/types/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ const char* Type::TypeName(Type::Code code) {
case Type::Code::DateTime64: return "DateTime64";
case Type::Code::Date32: return "Date32";
case Type::Code::Map: return "Map";
case Type::Code::Point: return "Point";
case Type::Code::Ring: return "Ring";
case Type::Code::Polygon: return "Polygon";
case Type::Code::MultiPolygon: return "MultiPolygon";
}

return "Unknown type";
Expand All @@ -72,6 +76,10 @@ std::string Type::GetName() const {
case IPv6:
case Date:
case Date32:
case Point:
case Ring:
case Polygon:
case MultiPolygon:
return TypeName(code_);
case FixedString:
return As<FixedStringType>()->GetName();
Expand Down Expand Up @@ -126,6 +134,10 @@ uint64_t Type::GetTypeUniqueId() const {
case IPv6:
case Date:
case Date32:
case Point:
case Ring:
case Polygon:
case MultiPolygon:
// For simple types, unique ID is the same as Type::Code
return code_;

Expand Down Expand Up @@ -233,6 +245,22 @@ TypeRef Type::CreateMap(TypeRef key_type, TypeRef value_type) {
return std::make_shared<MapType>(key_type, value_type);
}

TypeRef Type::CreatePoint() {
return TypeRef(new Type(Type::Point));
}

TypeRef Type::CreateRing() {
return TypeRef(new Type(Type::Ring));
}

TypeRef Type::CreatePolygon() {
return TypeRef(new Type(Type::Polygon));
}

TypeRef Type::CreateMultiPolygon() {
return TypeRef(new Type(Type::MultiPolygon));
}

/// class ArrayType

ArrayType::ArrayType(TypeRef item_type) : Type(Array), item_type_(item_type) {
Expand Down
14 changes: 13 additions & 1 deletion clickhouse/types/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ class Type {
LowCardinality,
DateTime64,
Date32,
Map
Map,
Point,
Ring,
Polygon,
MultiPolygon
};

using EnumItem = std::pair<std::string /* name */, int16_t /* value */>;
Expand Down Expand Up @@ -128,6 +132,14 @@ class Type {

static TypeRef CreateMap(TypeRef key_type, TypeRef value_type);

static TypeRef CreatePoint();

static TypeRef CreateRing();

static TypeRef CreatePolygon();

static TypeRef CreateMultiPolygon();

private:
uint64_t GetTypeUniqueId() const;

Expand Down
Loading

0 comments on commit 4251535

Please sign in to comment.