Skip to content

Commit 0dddc00

Browse files
committed
Add support for Time/Time64 columns
1 parent 4a278b5 commit 0dddc00

18 files changed

+493
-3
lines changed

clickhouse/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ SET ( clickhouse-cpp-lib-src
2121
columns/numeric.cpp
2222
columns/map.cpp
2323
columns/string.cpp
24+
columns/time.cpp
2425
columns/tuple.cpp
2526
columns/uuid.cpp
2627

clickhouse/client.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "columns/map.h"
1818
#include "columns/string.h"
1919
#include "columns/tuple.h"
20+
#include "columns/time.h"
2021
#include "columns/uuid.h"
2122

2223
#include <chrono>

clickhouse/columns/factory.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "nullable.h"
1515
#include "numeric.h"
1616
#include "string.h"
17+
#include "./time.h" // `./` avoids possible conflicts with standard C time.h
1718
#include "tuple.h"
1819
#include "uuid.h"
1920

@@ -108,7 +109,14 @@ static ColumnRef CreateTerminalColumn(const TypeAst& ast) {
108109
return std::make_shared<ColumnDate>();
109110
case Type::Date32:
110111
return std::make_shared<ColumnDate32>();
111-
112+
case Type::Time:
113+
return std::make_shared<ColumnTime>();
114+
case Type::Time64:
115+
if (ast.elements.empty()) {
116+
throw AssertionError("Time64 type without precision");
117+
} else {
118+
return std::make_shared<ColumnTime64>(GetASTChildElement(ast, 0).value);
119+
}
112120
case Type::IPv4:
113121
return std::make_shared<ColumnIPv4>();
114122
case Type::IPv6:

clickhouse/columns/itemview.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,15 @@ void ItemView::ValidateData(Type::Code type, DataType data) {
5959
case Type::Code::Date32:
6060
case Type::Code::IPv4:
6161
case Type::Code::Decimal32:
62+
case Type::Code::Time:
6263
return AssertSize({4});
6364

6465
case Type::Code::Int64:
6566
case Type::Code::UInt64:
6667
case Type::Code::Float64:
6768
case Type::Code::DateTime64:
6869
case Type::Code::Decimal64:
70+
case Type::Code::Time64:
6971
return AssertSize({8});
7072

7173
case Type::Code::String:

clickhouse/columns/time.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#include "time.h"
2+
3+
namespace clickhouse {
4+
5+
ColumnTime::ColumnTime()
6+
: ColumnTime(Type::CreateTime(), std::make_shared<ColumnInt32>()) {}
7+
8+
ColumnTime::ColumnTime(std::vector<int32_t>&& data)
9+
: ColumnTime(Type::CreateTime(), std::make_shared<ColumnInt32>(std::move(data))) {}
10+
11+
ColumnTime::ColumnTime(TypeRef type, std::shared_ptr<ColumnInt32> data)
12+
: Column(std::move(type)),
13+
data_(std::move(data))
14+
{}
15+
16+
void ColumnTime::Append(ValueType value) {
17+
data_->Append(value);
18+
}
19+
20+
ColumnTime::ValueType ColumnTime::At(size_t n) const {
21+
return data_->At(n);
22+
}
23+
24+
void ColumnTime::Reserve(size_t new_cap) {
25+
data_->Reserve(new_cap);
26+
}
27+
28+
void ColumnTime::Append(ColumnRef column) {
29+
if (auto col = column->As<ColumnTime>()) {
30+
data_->Append(col->data_);
31+
}
32+
}
33+
34+
bool ColumnTime::LoadBody(InputStream* input, size_t rows) {
35+
return data_->LoadBody(input, rows);
36+
}
37+
38+
void ColumnTime::Clear() {
39+
data_->Clear();
40+
}
41+
42+
void ColumnTime::SaveBody(OutputStream* output) {
43+
data_->SaveBody(output);
44+
}
45+
46+
size_t ColumnTime::Size() const {
47+
return data_->Size();
48+
}
49+
50+
ColumnRef ColumnTime::Slice(size_t begin, size_t len) const {
51+
auto sliced_data = data_->Slice(begin, len)->As<ColumnInt32>();
52+
return ColumnRef{new ColumnTime(type_, sliced_data)};
53+
}
54+
55+
ColumnRef ColumnTime::CloneEmpty() const {
56+
return ColumnRef{new ColumnTime(type_, data_->CloneEmpty()->As<ColumnInt32>())};
57+
}
58+
59+
void ColumnTime::Swap(Column& other) {
60+
auto & col = dynamic_cast<ColumnTime &>(other);
61+
data_.swap(col.data_);
62+
}
63+
64+
ItemView ColumnTime::GetItem(size_t index) const {
65+
return ItemView{Type::Time, data_->GetItem(index)};
66+
}
67+
68+
ColumnTime64::ColumnTime64(size_t precision)
69+
: ColumnTime64(Type::CreateTime64(precision), std::make_shared<ColumnInt64>())
70+
{}
71+
72+
ColumnTime64::ColumnTime64(size_t precision, std::vector<int64_t>&& data)
73+
: ColumnTime64(Type::CreateTime64(precision), std::make_shared<ColumnInt64>(std::move(data)))
74+
{}
75+
76+
ColumnTime64::ColumnTime64(TypeRef type, std::shared_ptr<ColumnInt64> data)
77+
: Column(std::move(type)),
78+
data_(std::move(data)),
79+
precision_{type_->As<Time64Type>()->GetPrecision()}
80+
{}
81+
82+
void ColumnTime64::Append(ValueType value) {
83+
data_->Append(value);
84+
}
85+
86+
ColumnTime64::ValueType ColumnTime64::At(size_t n) const {
87+
return data_->At(n);
88+
}
89+
90+
void ColumnTime64::Reserve(size_t new_cap) {
91+
data_->Reserve(new_cap);
92+
}
93+
94+
void ColumnTime64::Append(ColumnRef column) {
95+
if (auto col = column->As<ColumnTime64>()) {
96+
data_->Append(col->data_);
97+
}
98+
}
99+
100+
bool ColumnTime64::LoadBody(InputStream* input, size_t rows) {
101+
return data_->LoadBody(input, rows);
102+
}
103+
104+
void ColumnTime64::Clear() {
105+
data_->Clear();
106+
}
107+
108+
void ColumnTime64::SaveBody(OutputStream* output) {
109+
data_->SaveBody(output);
110+
}
111+
112+
size_t ColumnTime64::Size() const {
113+
return data_->Size();
114+
}
115+
116+
ColumnRef ColumnTime64::Slice(size_t begin, size_t len) const {
117+
auto sliced_data = data_->Slice(begin, len)->As<ColumnInt64>();
118+
return ColumnRef{new ColumnTime64(type_, sliced_data)};
119+
}
120+
121+
ColumnRef ColumnTime64::CloneEmpty() const {
122+
return ColumnRef{new ColumnTime64(type_, data_->CloneEmpty()->As<ColumnInt64>())};
123+
}
124+
125+
void ColumnTime64::Swap(Column& other) {
126+
auto & col = dynamic_cast<ColumnTime64 &>(other);
127+
if (col.GetPrecision() != GetPrecision()) {
128+
throw ValidationError("Can't swap Time64 columns when precisions are not the same: "
129+
+ std::to_string(GetPrecision()) + "(this) != "
130+
+ std::to_string(col.GetPrecision()) + "(that)");
131+
}
132+
data_.swap(col.data_);
133+
}
134+
135+
ItemView ColumnTime64::GetItem(size_t index) const {
136+
return ItemView{Type::Time64, data_->GetItem(index)};
137+
}
138+
139+
} // namespace clickhouse

clickhouse/columns/time.h

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#pragma once
2+
3+
#include "column.h"
4+
#include "numeric.h"
5+
6+
namespace clickhouse {
7+
8+
class ColumnTime : public Column {
9+
public:
10+
using ValueType = int32_t;
11+
12+
ColumnTime();
13+
explicit ColumnTime(std::vector<int32_t>&& data);
14+
15+
/// Appends one element to the end of column.
16+
void Append(ValueType value);
17+
18+
/// Returns element at given row number.
19+
ValueType At(size_t n) const;
20+
21+
ValueType operator[](size_t n) const { return At(n); }
22+
23+
public:
24+
/// Increase the capacity of the column for large block insertion.
25+
void Reserve(size_t new_cap) override;
26+
27+
/// Appends content of given column to the end of current one.
28+
void Append(ColumnRef column) override;
29+
30+
/// Loads column data from input stream.
31+
bool LoadBody(InputStream* input, size_t rows) override;
32+
33+
/// Clear column data .
34+
void Clear() override;
35+
36+
/// Saves column data to output stream.
37+
void SaveBody(OutputStream* output) override;
38+
39+
/// Returns count of rows in the column.
40+
size_t Size() const override;
41+
42+
/// Makes slice of the current column.
43+
ColumnRef Slice(size_t begin, size_t len) const override;
44+
ColumnRef CloneEmpty() const override;
45+
void Swap(Column& other) override;
46+
47+
ItemView GetItem(size_t index) const override;
48+
49+
private:
50+
ColumnTime(TypeRef type, std::shared_ptr<ColumnInt32> data);
51+
52+
private:
53+
std::shared_ptr<ColumnInt32> data_;
54+
};
55+
56+
class ColumnTime64 : public Column {
57+
public:
58+
using ValueType = int64_t;
59+
60+
explicit ColumnTime64(size_t precision);
61+
ColumnTime64(size_t precision, std::vector<int64_t>&& data);
62+
63+
/// Appends one element to the end of column.
64+
void Append(ValueType value);
65+
66+
/// Returns element at given row number.
67+
ValueType At(size_t n) const;
68+
69+
ValueType operator[](size_t n) const { return At(n); }
70+
71+
public:
72+
/// Increase the capacity of the column for large block insertion.
73+
void Reserve(size_t new_cap) override;
74+
75+
/// Appends content of given column to the end of current one.
76+
void Append(ColumnRef column) override;
77+
78+
/// Loads column data from input stream.
79+
bool LoadBody(InputStream* input, size_t rows) override;
80+
81+
/// Clear column data .
82+
void Clear() override;
83+
84+
/// Saves column data to output stream.
85+
void SaveBody(OutputStream* output) override;
86+
87+
/// Returns count of rows in the column.
88+
size_t Size() const override;
89+
90+
/// Makes slice of the current column.
91+
ColumnRef Slice(size_t begin, size_t len) const override;
92+
ColumnRef CloneEmpty() const override;
93+
void Swap(Column& other) override;
94+
95+
ItemView GetItem(size_t index) const override;
96+
97+
size_t GetPrecision() const { return precision_; };
98+
99+
private:
100+
ColumnTime64(TypeRef type, std::shared_ptr<ColumnInt64> data);
101+
102+
private:
103+
std::shared_ptr<ColumnInt64> data_;
104+
const size_t precision_;
105+
};
106+
107+
}

clickhouse/types/type_parser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ static const std::unordered_map<std::string, Type::Code> kTypeCode = {
6565
{ "Ring", Type::Ring },
6666
{ "Polygon", Type::Polygon },
6767
{ "MultiPolygon", Type::MultiPolygon },
68+
{ "Time", Type::Time },
69+
{ "Time64", Type::Time64 },
6870
};
6971

7072
template <typename L, typename R>

clickhouse/types/types.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ const char* Type::TypeName(Type::Code code) {
5252
case Type::Code::Ring: return "Ring";
5353
case Type::Code::Polygon: return "Polygon";
5454
case Type::Code::MultiPolygon: return "MultiPolygon";
55+
case Type::Code::Time: return "Time";
56+
case Type::Code::Time64: return "Time64";
5557
}
5658

5759
return "Unknown type";
@@ -78,11 +80,14 @@ std::string Type::GetName() const {
7880
case IPv6:
7981
case Date:
8082
case Date32:
83+
case Time:
8184
case Point:
8285
case Ring:
8386
case Polygon:
8487
case MultiPolygon:
8588
return TypeName(code_);
89+
case Time64:
90+
return As<Time64Type>()->GetName();
8691
case FixedString:
8792
return As<FixedStringType>()->GetName();
8893
case DateTime:
@@ -145,6 +150,8 @@ uint64_t Type::GetTypeUniqueId() const {
145150
return code_;
146151

147152
case FixedString:
153+
case Time:
154+
case Time64:
148155
case DateTime:
149156
case DateTime64:
150157
case Array:
@@ -188,6 +195,14 @@ TypeRef Type::CreateDate32() {
188195
return TypeRef(new Type(Type::Date32));
189196
}
190197

198+
TypeRef Type::CreateTime() {
199+
return TypeRef(new Type(Type::Time));
200+
}
201+
202+
TypeRef Type::CreateTime64(size_t precision) {
203+
return TypeRef(new Time64Type(precision));
204+
}
205+
191206
TypeRef Type::CreateDateTime(std::string timezone) {
192207
return TypeRef(new DateTimeType(std::move(timezone)));
193208
}
@@ -366,6 +381,18 @@ const std::string & TypeWithTimeZoneMixin::Timezone() const {
366381
}
367382
}
368383

384+
/// class Time64
385+
Time64Type::Time64Type(size_t precision)
386+
: Type(Time64), precision_{precision} {
387+
if (precision_ > 9) {
388+
throw ValidationError("Time64 precision is > 9");
389+
}
390+
}
391+
392+
std::string Time64Type::GetName() const {
393+
return "Time64(" + std::to_string(precision_) + ")";
394+
}
395+
369396
/// class DateTimeType
370397
DateTimeType::DateTimeType(std::string timezone)
371398
: Type(DateTime), details::TypeWithTimeZoneMixin(std::move(timezone)) {

0 commit comments

Comments
 (0)