Skip to content

Commit 20dd563

Browse files
authored
Merge pull request #66 from ClickHouse/artpaul_119
use absl for int128
2 parents 13079ad + 63288eb commit 20dd563

24 files changed

+4920
-54
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ PROJECT (CLICKHOUSE-CLIENT)
2828

2929
SUBDIRS (
3030
clickhouse
31+
contrib/absl
3132
contrib/cityhash
3233
contrib/lz4
3334
)

clickhouse/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ SET ( clickhouse-cpp-lib-src
3434
ADD_LIBRARY (clickhouse-cpp-lib SHARED ${clickhouse-cpp-lib-src})
3535
SET_TARGET_PROPERTIES(clickhouse-cpp-lib PROPERTIES LINKER_LANGUAGE CXX)
3636
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib
37+
absl-lib
3738
cityhash-lib
3839
lz4-lib
3940
)
4041

4142
ADD_LIBRARY (clickhouse-cpp-lib-static STATIC ${clickhouse-cpp-lib-src})
4243
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib-static
44+
absl-lib
4345
cityhash-lib
4446
lz4-lib
4547
)

clickhouse/columns/date.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ void ColumnDateTime64::Append(const Int64& value) {
148148
//}
149149

150150
Int64 ColumnDateTime64::At(size_t n) const {
151-
return data_->At(n);
151+
// make sure to use Absl's Int128 conversion
152+
return static_cast<Int64>(data_->At(n));
152153
}
153154

154155
std::string ColumnDateTime64::Timezone() const {

clickhouse/columns/decimal.cpp

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,102 @@
11
#include "decimal.h"
22

3+
namespace
4+
{
5+
using namespace clickhouse;
6+
7+
#ifdef ABSL_HAVE_INTRINSIC_INT128
8+
template <typename T>
9+
inline bool addOverflow(const Int128 & l, const T & r, Int128 * result)
10+
{
11+
__int128 res;
12+
const auto ret_value = __builtin_add_overflow(static_cast<__int128>(l), static_cast<__int128>(r), &res);
13+
14+
*result = res;
15+
return ret_value;
16+
}
17+
18+
template <typename T>
19+
inline bool mulOverflow(const Int128 & l, const T & r, Int128 * result)
20+
{
21+
__int128 res;
22+
const auto ret_value = __builtin_mul_overflow(static_cast<__int128>(l), static_cast<__int128>(r), &res);
23+
24+
*result = res;
25+
return ret_value;
26+
}
27+
28+
#else
29+
template <typename T>
30+
inline bool getSignBit(const T & v)
31+
{
32+
return std::signbit(v);
33+
}
34+
35+
inline bool getSignBit(const Int128 & v)
36+
{
37+
// static constexpr Int128 zero {};
38+
// return v < zero;
39+
40+
// Sign of the whole absl::int128 value is determined by sign of higher 64 bits.
41+
return absl::Int128High64(v) < 0;
42+
}
43+
44+
inline bool addOverflow(const Int128 & l, const Int128 & r, Int128 * result)
45+
{
46+
// *result = l + r;
47+
// const auto result_sign = getSignBit(*result);
48+
// return l_sign == r_sign && l_sign != result_sign;
49+
50+
// Based on code from:
51+
// https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow#INT32C.Ensurethatoperationsonsignedintegersdonotresultinoverflow-CompliantSolution
52+
const auto r_positive = !getSignBit(r);
53+
54+
if ((r_positive && (l > (std::numeric_limits<Int128>::max() - r))) ||
55+
(!r_positive && (l < (std::numeric_limits<Int128>::min() - r)))) {
56+
return true;
57+
}
58+
*result = l + r;
59+
60+
return false;
61+
}
62+
63+
template <typename T>
64+
inline bool mulOverflow(const Int128 & l, const T & r, Int128 * result)
65+
{
66+
// Based on code from:
67+
// https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow#INT32C.Ensurethatoperationsonsignedintegersdonotresultinoverflow-CompliantSolution.3
68+
const auto l_positive = !getSignBit(l);
69+
const auto r_positive = !getSignBit(r);
70+
71+
if (l_positive) {
72+
if (r_positive) {
73+
if (r != 0 && l > (std::numeric_limits<Int128>::max() / r)) {
74+
return true;
75+
}
76+
} else {
77+
if (l != 0 && r < (std::numeric_limits<Int128>::min() / l)) {
78+
return true;
79+
}
80+
}
81+
} else {
82+
if (r_positive) {
83+
if (r != 0 && l < (std::numeric_limits<Int128>::min() / r)) {
84+
return true;
85+
}
86+
} else {
87+
if (l != 0 && (r < (std::numeric_limits<Int128>::max() / l))) {
88+
return true;
89+
}
90+
}
91+
}
92+
93+
*result = l * r;
94+
return false;
95+
}
96+
#endif
97+
98+
}
99+
3100
namespace clickhouse {
4101

5102
ColumnDecimal::ColumnDecimal(size_t precision, size_t scale)
@@ -57,8 +154,8 @@ void ColumnDecimal::Append(const std::string& value) {
57154

58155
has_dot = true;
59156
} else if (*c >= '0' && *c <= '9') {
60-
if (__builtin_mul_overflow(int_value, 10, &int_value) ||
61-
__builtin_add_overflow(int_value, *c - '0', &int_value)) {
157+
if (mulOverflow(int_value, 10, &int_value) ||
158+
addOverflow(int_value, *c - '0', &int_value)) {
62159
throw std::runtime_error("value is too big for 128-bit integer");
63160
}
64161
} else {
@@ -72,7 +169,7 @@ void ColumnDecimal::Append(const std::string& value) {
72169
}
73170

74171
while (zeros) {
75-
if (__builtin_mul_overflow(int_value, 10, &int_value)) {
172+
if (mulOverflow(int_value, 10, &int_value)) {
76173
throw std::runtime_error("value is too big for 128-bit integer");
77174
}
78175
--zeros;

clickhouse/columns/itemview.cpp

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,69 @@
33
namespace clickhouse {
44

55
void ItemView::ValidateData(Type::Code type, DataType data) {
6-
static const int ANY = -1; // value can be of any size
7-
static const int ERR = -2; // value is not allowed inside ItemView
8-
static const int value_size_by_type[] = {
9-
0, /*Void*/
10-
1, /*Int8*/
11-
2, /*Int16*/
12-
4, /*Int32*/
13-
8, /*Int64*/
14-
1, /*UInt8*/
15-
2, /*UInt16*/
16-
4, /*UInt32*/
17-
8, /*UInt64*/
18-
4, /*Float32*/
19-
8, /*Float64*/
20-
ANY, /*String*/
21-
ANY, /*FixedString*/
22-
4, /*DateTime*/
23-
8, /*DateTime64*/
24-
2, /*Date*/
25-
ERR, /*Array*/
26-
ERR, /*Nullable*/
27-
ERR, /*Tuple*/
28-
1, /*Enum8*/
29-
2, /*Enum16*/
30-
16, /*UUID*/
31-
4, /*IPv4*/
32-
8, /*IPv6*/
33-
16, /*Int128*/
34-
16, /*Decimal*/
35-
4, /*Decimal32*/
36-
8, /*Decimal64*/
37-
16, /*Decimal128*/
38-
ERR, /*LowCardinality*/
39-
};
40-
41-
if (type >= sizeof(value_size_by_type)/sizeof(value_size_by_type[0]) || type < 0) {
42-
throw std::runtime_error("Unknon type code:" + std::to_string(static_cast<int>(type)));
43-
} else {
44-
const auto expected_size = value_size_by_type[type];
45-
if (expected_size == ERR) {
6+
int expected_size = 0;
7+
switch (type) {
8+
case Type::Code::Void:
9+
expected_size = 0;
10+
break;
11+
12+
case Type::Code::Int8:
13+
case Type::Code::UInt8:
14+
case Type::Code::Enum8:
15+
expected_size = 1;
16+
break;
17+
18+
case Type::Code::Int16:
19+
case Type::Code::UInt16:
20+
case Type::Code::Date:
21+
case Type::Code::Enum16:
22+
expected_size = 2;
23+
break;
24+
25+
case Type::Code::Int32:
26+
case Type::Code::UInt32:
27+
case Type::Code::Float32:
28+
case Type::Code::DateTime:
29+
case Type::Code::IPv4:
30+
case Type::Code::Decimal32:
31+
expected_size = 4;
32+
break;
33+
34+
case Type::Code::Int64:
35+
case Type::Code::UInt64:
36+
case Type::Code::Float64:
37+
case Type::Code::DateTime64:
38+
case Type::Code::IPv6:
39+
case Type::Code::Decimal64:
40+
expected_size = 8;
41+
break;
42+
43+
case Type::Code::String:
44+
case Type::Code::FixedString:
45+
// value can be of any size
46+
return;
47+
48+
case Type::Code::Array:
49+
case Type::Code::Nullable:
50+
case Type::Code::Tuple:
51+
case Type::Code::LowCardinality:
4652
throw std::runtime_error("Unsupported type in ItemView: " + std::to_string(static_cast<int>(type)));
47-
} else if (expected_size != ANY && expected_size != static_cast<int>(data.size())) {
48-
throw std::runtime_error("Value size mismatch for type "
49-
+ std::to_string(static_cast<int>(type)) + " expected: "
50-
+ std::to_string(expected_size) + ", got: " + std::to_string(data.size()));
51-
}
53+
54+
case Type::Code::UUID:
55+
case Type::Code::Int128:
56+
case Type::Code::Decimal:
57+
case Type::Code::Decimal128:
58+
expected_size = 16;
59+
break;
60+
61+
default:
62+
throw std::runtime_error("Unknon type code:" + std::to_string(static_cast<int>(type)));
63+
}
64+
65+
if (expected_size != static_cast<int>(data.size())) {
66+
throw std::runtime_error("Value size mismatch for type "
67+
+ std::to_string(static_cast<int>(type)) + " expected: "
68+
+ std::to_string(expected_size) + ", got: " + std::to_string(data.size()));
5269
}
5370
}
5471

clickhouse/columns/itemview.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ struct ItemView {
2626
inline auto ConvertToStorageValue(const T& t) {
2727
if constexpr (std::is_same_v<std::string_view, T> || std::is_same_v<std::string, T>) {
2828
return std::string_view{t};
29-
} else if constexpr (std::is_fundamental_v<T>) {
29+
} else if constexpr (std::is_fundamental_v<T> || std::is_same_v<Int128, std::decay_t<T>>) {
3030
return std::string_view{reinterpret_cast<const char*>(&t), sizeof(T)};
3131
} else {
32-
// will caue error at compile-time
32+
static_assert(!std::is_same_v<T, T>, "Unknown type, which can't be stored in ItemView");
3333
return;
3434
}
3535
}
@@ -55,7 +55,7 @@ struct ItemView {
5555
T get() const {
5656
if constexpr (std::is_same_v<std::string_view, T> || std::is_same_v<std::string, T>) {
5757
return data;
58-
} else if constexpr (std::is_fundamental_v<T>) {
58+
} else if constexpr (std::is_fundamental_v<T> || std::is_same_v<Int128, T>) {
5959
if (sizeof(T) == data.size()) {
6060
return *reinterpret_cast<const T*>(data.data());
6161
} else {

clickhouse/columns/numeric.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "column.h"
4+
#include "absl/numeric/int128.h"
45

56
namespace clickhouse {
67

@@ -54,7 +55,7 @@ class ColumnVector : public Column {
5455
std::vector<T> data_;
5556
};
5657

57-
using Int128 = __int128;
58+
using Int128 = absl::int128;
5859
using Int64 = int64_t;
5960

6061
using ColumnUInt8 = ColumnVector<uint8_t>;

clickhouse/types/types.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "absl/numeric/int128.h"
4+
35
#include <map>
46
#include <memory>
57
#include <string>
@@ -8,6 +10,9 @@
810

911
namespace clickhouse {
1012

13+
using Int128 = absl::int128;
14+
using Int64 = int64_t;
15+
1116
using TypeRef = std::shared_ptr<class Type>;
1217

1318
class Type {
@@ -280,7 +285,7 @@ inline TypeRef Type::CreateSimple<int64_t>() {
280285
}
281286

282287
template <>
283-
inline TypeRef Type::CreateSimple<__int128>() {
288+
inline TypeRef Type::CreateSimple<absl::int128>() {
284289
return TypeRef(new Type(Int128));
285290
}
286291

contrib/absl/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ADD_LIBRARY (absl-lib STATIC
2+
numeric/int128.cc
3+
)

0 commit comments

Comments
 (0)