Skip to content

Commit 4251535

Browse files
authored
Merge pull request #258 from den818/Geo
Support geo column types
2 parents 0472da2 + bac2967 commit 4251535

13 files changed

+371
-17
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ C++ client for [ClickHouse](https://clickhouse.com/).
2222
* Int128
2323
* UUID
2424
* Map
25+
* Point, Ring, Polygon, MultiPolygon
2526

2627
## Building
2728

Diff for: clickhouse/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SET ( clickhouse-cpp-lib-src
1212
columns/decimal.cpp
1313
columns/enum.cpp
1414
columns/factory.cpp
15+
columns/geo.cpp
1516
columns/ip4.cpp
1617
columns/ip6.cpp
1718
columns/lowcardinality.cpp
@@ -117,6 +118,7 @@ INSTALL(FILES columns/date.h DESTINATION include/clickhouse/columns/)
117118
INSTALL(FILES columns/decimal.h DESTINATION include/clickhouse/columns/)
118119
INSTALL(FILES columns/enum.h DESTINATION include/clickhouse/columns/)
119120
INSTALL(FILES columns/factory.h DESTINATION include/clickhouse/columns/)
121+
INSTALL(FILES columns/geo.h DESTINATION include/clickhouse/columns/)
120122
INSTALL(FILES columns/ip4.h DESTINATION include/clickhouse/columns/)
121123
INSTALL(FILES columns/ip6.h DESTINATION include/clickhouse/columns/)
122124
INSTALL(FILES columns/itemview.h DESTINATION include/clickhouse/columns/)

Diff for: clickhouse/client.h

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "columns/date.h"
88
#include "columns/decimal.h"
99
#include "columns/enum.h"
10+
#include "columns/geo.h"
1011
#include "columns/ip4.h"
1112
#include "columns/ip6.h"
1213
#include "columns/lowcardinality.h"

Diff for: clickhouse/columns/factory.cpp

+15-1
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44
#include "date.h"
55
#include "decimal.h"
66
#include "enum.h"
7+
#include "geo.h"
78
#include "ip4.h"
89
#include "ip6.h"
910
#include "lowcardinality.h"
1011
#include "lowcardinalityadaptor.h"
12+
#include "map.h"
1113
#include "nothing.h"
1214
#include "nullable.h"
1315
#include "numeric.h"
1416
#include "string.h"
1517
#include "tuple.h"
1618
#include "uuid.h"
17-
#include "map.h"
19+
1820

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

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

102+
case Type::Point:
103+
return std::make_shared<ColumnPoint>();
104+
105+
case Type::Ring:
106+
return std::make_shared<ColumnRing>();
107+
108+
case Type::Polygon:
109+
return std::make_shared<ColumnPolygon>();
110+
111+
case Type::MultiPolygon:
112+
return std::make_shared<ColumnMultiPolygon>();
113+
100114
default:
101115
return nullptr;
102116
}

Diff for: clickhouse/columns/geo.cpp

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#include "geo.h"
2+
3+
#include "utils.h"
4+
5+
namespace {
6+
using namespace ::clickhouse;
7+
8+
template <Type::Code type_code>
9+
TypeRef CreateGeoType() {
10+
if constexpr (type_code == Type::Code::Point) {
11+
return Type::CreatePoint();
12+
} else if constexpr (type_code == Type::Code::Ring) {
13+
return Type::CreateRing();
14+
} else if constexpr (type_code == Type::Code::Polygon) {
15+
return Type::CreatePolygon();
16+
} else if constexpr (type_code == Type::Code::MultiPolygon) {
17+
return Type::CreateMultiPolygon();
18+
}
19+
}
20+
21+
template <typename ColumnType>
22+
std::shared_ptr<ColumnType> CreateColumn() {
23+
if constexpr (std::is_same_v<ColumnType, ColumnTupleT<ColumnFloat64, ColumnFloat64>>) {
24+
return std::make_shared<ColumnTupleT<ColumnFloat64, ColumnFloat64>>(
25+
std::make_tuple(std::make_shared<ColumnFloat64>(), std::make_shared<ColumnFloat64>()));
26+
} else {
27+
return std::make_shared<ColumnType>();
28+
}
29+
}
30+
31+
} // namespace
32+
33+
namespace clickhouse {
34+
35+
template <typename NestedColumnType, Type::Code type_code>
36+
ColumnGeo<NestedColumnType, type_code>::ColumnGeo()
37+
: Column(std::move(CreateGeoType<type_code>())),
38+
data_(std::move(CreateColumn<NestedColumnType>())) {
39+
}
40+
41+
template <typename NestedColumnType, Type::Code type_code>
42+
ColumnGeo<NestedColumnType, type_code>::ColumnGeo(ColumnRef data)
43+
: Column(std::move(CreateGeoType<type_code>()))
44+
, data_(std::move(WrapColumn<NestedColumnType>(std::move(data)))) {
45+
}
46+
47+
template <typename NestedColumnType, Type::Code type_code>
48+
void ColumnGeo<NestedColumnType, type_code>::Clear() {
49+
data_->Clear();
50+
}
51+
52+
template <typename NestedColumnType, Type::Code type_code>
53+
const typename ColumnGeo<NestedColumnType, type_code>::ValueType ColumnGeo<NestedColumnType, type_code>::At(size_t n) const {
54+
return data_->At(n);
55+
}
56+
57+
template <typename NestedColumnType, Type::Code type_code>
58+
const typename ColumnGeo<NestedColumnType, type_code>::ValueType ColumnGeo<NestedColumnType, type_code>::operator[](size_t n) const {
59+
return data_->At(n);
60+
}
61+
62+
template <typename NestedColumnType, Type::Code type_code>
63+
void ColumnGeo<NestedColumnType, type_code>::Append(ColumnRef column) {
64+
if (auto col = column->template As<ColumnGeo>()) {
65+
data_->Append(col->data_->template As<Column>());
66+
}
67+
}
68+
69+
template <typename NestedColumnType, Type::Code type_code>
70+
bool ColumnGeo<NestedColumnType, type_code>::LoadBody(InputStream* input, size_t rows) {
71+
return data_->LoadBody(input, rows);
72+
}
73+
74+
template <typename NestedColumnType, Type::Code type_code>
75+
void ColumnGeo<NestedColumnType, type_code>::SaveBody(OutputStream* output) {
76+
data_->SaveBody(output);
77+
}
78+
79+
template <typename NestedColumnType, Type::Code type_code>
80+
size_t ColumnGeo<NestedColumnType, type_code>::Size() const {
81+
return data_->Size();
82+
}
83+
84+
template <typename NestedColumnType, Type::Code type_code>
85+
ColumnRef ColumnGeo<NestedColumnType, type_code>::Slice(size_t begin, size_t len) const {
86+
return std::make_shared<ColumnGeo>(data_->Slice(begin, len));
87+
}
88+
89+
template <typename NestedColumnType, Type::Code type_code>
90+
ColumnRef ColumnGeo<NestedColumnType, type_code>::CloneEmpty() const {
91+
return std::make_shared<ColumnGeo>();
92+
}
93+
94+
template <typename NestedColumnType, Type::Code type_code>
95+
void ColumnGeo<NestedColumnType, type_code>::Swap(Column& other) {
96+
auto& col = dynamic_cast<ColumnGeo&>(other);
97+
data_.swap(col.data_);
98+
}
99+
100+
template class ColumnGeo<ColumnTupleT<ColumnFloat64, ColumnFloat64>, Type::Code::Point>;
101+
102+
template class ColumnGeo<ColumnArrayT<ColumnPoint>, Type::Code::Ring>;
103+
104+
template class ColumnGeo<ColumnArrayT<ColumnRing>, Type::Code::Polygon>;
105+
106+
template class ColumnGeo<ColumnArrayT<ColumnPolygon>, Type::Code::MultiPolygon>;
107+
108+
} // namespace clickhouse

Diff for: clickhouse/columns/geo.h

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#pragma once
2+
3+
#include "array.h"
4+
#include "column.h"
5+
#include "numeric.h"
6+
#include "tuple.h"
7+
8+
namespace clickhouse {
9+
10+
template <typename NestedColumnType, Type::Code type_code>
11+
class ColumnGeo : public Column {
12+
public:
13+
using ValueType = typename NestedColumnType::ValueType;
14+
15+
ColumnGeo();
16+
17+
explicit ColumnGeo(ColumnRef data);
18+
19+
/// Appends one element to the end of column.
20+
template <typename T = ValueType>
21+
void Append(const T& value) {
22+
data_->Append(value);
23+
}
24+
25+
/// Returns element at given row number.
26+
const ValueType At(size_t n) const;
27+
28+
/// Returns element at given row number.
29+
const ValueType operator[](size_t n) const;
30+
31+
public:
32+
/// Appends content of given column to the end of current one.
33+
void Append(ColumnRef column) override;
34+
35+
/// Loads column data from input stream.
36+
bool LoadBody(InputStream* input, size_t rows) override;
37+
38+
/// Saves column data to output stream.
39+
void SaveBody(OutputStream* output) override;
40+
41+
/// Clear column data .
42+
void Clear() override;
43+
44+
/// Returns count of rows in the column.
45+
size_t Size() const override;
46+
47+
/// Makes slice of the current column.
48+
ColumnRef Slice(size_t begin, size_t len) const override;
49+
ColumnRef CloneEmpty() const override;
50+
void Swap(Column& other) override;
51+
52+
private:
53+
std::shared_ptr<NestedColumnType> data_;
54+
};
55+
56+
// /**
57+
// * Represents a Point column.
58+
// */
59+
using ColumnPoint = ColumnGeo<ColumnTupleT<ColumnFloat64, ColumnFloat64>, Type::Code::Point>;
60+
61+
/**
62+
* Represents a Ring column.
63+
*/
64+
using ColumnRing = ColumnGeo<ColumnArrayT<ColumnPoint>, Type::Code::Ring>;
65+
66+
/**
67+
* Represents a Polygon column.
68+
*/
69+
using ColumnPolygon = ColumnGeo<ColumnArrayT<ColumnRing>, Type::Code::Polygon>;
70+
71+
/**
72+
* Represents a MultiPolygon column.
73+
*/
74+
using ColumnMultiPolygon = ColumnGeo<ColumnArrayT<ColumnPolygon>, Type::Code::MultiPolygon>;
75+
76+
} // namespace clickhouse

Diff for: clickhouse/columns/tuple.h

+17-10
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,11 @@ class ColumnTupleT : public ColumnTuple {
7676

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

79-
template <typename T, size_t index = std::tuple_size_v<T>>
80-
inline void Append([[maybe_unused]] T value) {
81-
static_assert(index <= std::tuple_size_v<T>);
82-
static_assert(std::tuple_size_v<TupleOfColumns> == std::tuple_size_v<T>);
83-
if constexpr (index == 0) {
84-
return;
85-
} else {
86-
std::get<index - 1>(typed_columns_)->Append(std::move(std::get<index - 1>(value)));
87-
Append<T, index - 1>(std::move(value));
88-
}
79+
using ColumnTuple::Append;
80+
81+
template <typename... T>
82+
inline void Append(std::tuple<T...> value) {
83+
AppendTuple(std::move(value));
8984
}
9085

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

124119
private:
120+
template <typename T, size_t index = std::tuple_size_v<T>>
121+
inline void AppendTuple([[maybe_unused]] T value) {
122+
static_assert(index <= std::tuple_size_v<T>);
123+
static_assert(std::tuple_size_v<TupleOfColumns> == std::tuple_size_v<T>);
124+
if constexpr (index == 0) {
125+
return;
126+
} else {
127+
std::get<index - 1>(typed_columns_)->Append(std::move(std::get<index - 1>(value)));
128+
AppendTuple<T, index - 1>(std::move(value));
129+
}
130+
}
131+
125132
template <typename T, size_t index = std::tuple_size_v<T>>
126133
inline static std::vector<ColumnRef> TupleToVector([[maybe_unused]] const T& value) {
127134
static_assert(index <= std::tuple_size_v<T>);

Diff for: clickhouse/types/type_parser.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ static const std::unordered_map<std::string, Type::Code> kTypeCode = {
4646
{ "Decimal64", Type::Decimal64 },
4747
{ "Decimal128", Type::Decimal128 },
4848
{ "LowCardinality", Type::LowCardinality },
49-
{ "Map", Type::Map},
49+
{ "Map", Type::Map},
50+
{ "Point", Type::Point},
51+
{ "Ring", Type::Ring},
52+
{ "Polygon", Type::Polygon},
53+
{ "MultiPolygon", Type::MultiPolygon},
5054
};
5155

5256
static Type::Code GetTypeCode(const std::string& name) {

Diff for: clickhouse/types/types.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ const char* Type::TypeName(Type::Code code) {
4747
case Type::Code::DateTime64: return "DateTime64";
4848
case Type::Code::Date32: return "Date32";
4949
case Type::Code::Map: return "Map";
50+
case Type::Code::Point: return "Point";
51+
case Type::Code::Ring: return "Ring";
52+
case Type::Code::Polygon: return "Polygon";
53+
case Type::Code::MultiPolygon: return "MultiPolygon";
5054
}
5155

5256
return "Unknown type";
@@ -72,6 +76,10 @@ std::string Type::GetName() const {
7276
case IPv6:
7377
case Date:
7478
case Date32:
79+
case Point:
80+
case Ring:
81+
case Polygon:
82+
case MultiPolygon:
7583
return TypeName(code_);
7684
case FixedString:
7785
return As<FixedStringType>()->GetName();
@@ -126,6 +134,10 @@ uint64_t Type::GetTypeUniqueId() const {
126134
case IPv6:
127135
case Date:
128136
case Date32:
137+
case Point:
138+
case Ring:
139+
case Polygon:
140+
case MultiPolygon:
129141
// For simple types, unique ID is the same as Type::Code
130142
return code_;
131143

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

248+
TypeRef Type::CreatePoint() {
249+
return TypeRef(new Type(Type::Point));
250+
}
251+
252+
TypeRef Type::CreateRing() {
253+
return TypeRef(new Type(Type::Ring));
254+
}
255+
256+
TypeRef Type::CreatePolygon() {
257+
return TypeRef(new Type(Type::Polygon));
258+
}
259+
260+
TypeRef Type::CreateMultiPolygon() {
261+
return TypeRef(new Type(Type::MultiPolygon));
262+
}
263+
236264
/// class ArrayType
237265

238266
ArrayType::ArrayType(TypeRef item_type) : Type(Array), item_type_(item_type) {

Diff for: clickhouse/types/types.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ class Type {
5050
LowCardinality,
5151
DateTime64,
5252
Date32,
53-
Map
53+
Map,
54+
Point,
55+
Ring,
56+
Polygon,
57+
MultiPolygon
5458
};
5559

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

129133
static TypeRef CreateMap(TypeRef key_type, TypeRef value_type);
130134

135+
static TypeRef CreatePoint();
136+
137+
static TypeRef CreateRing();
138+
139+
static TypeRef CreatePolygon();
140+
141+
static TypeRef CreateMultiPolygon();
142+
131143
private:
132144
uint64_t GetTypeUniqueId() const;
133145

0 commit comments

Comments
 (0)