Skip to content

Commit 6ff8e4b

Browse files
committed
Add GetString to ColumnDecimal.
It converts the internal integer to a decimal string relative to the scale and precision.
1 parent b8544bb commit 6ff8e4b

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

clickhouse/columns/decimal.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <sstream>
12
#include "decimal.h"
23

34
namespace
@@ -246,4 +247,42 @@ size_t ColumnDecimal::GetPrecision() const
246247
return type_->As<DecimalType>()->GetPrecision();
247248
}
248249

250+
std::string ColumnDecimal::GetString(size_t index) const {
251+
auto val = At(index);
252+
253+
// Convert the Int128 to a string.
254+
std::stringstream ss;
255+
ss << val;
256+
std::string str = ss.str();
257+
258+
// Start a destination string.
259+
std::stringstream res;
260+
auto scale = GetScale();
261+
262+
// Output a dash for negative values
263+
if (val < 0) {
264+
res << '-';
265+
str.erase(0, 1);
266+
}
267+
268+
if (scale == 0) {
269+
// No decimal point, just output the entire value.
270+
res << str;
271+
} else if (str.length() <= scale) {
272+
// Append the entire value prepended with zeros after the decimal.
273+
res << "0." << std::string(scale-str.length(), '0') << str;
274+
} else {
275+
// There are digits before the decimal.
276+
auto decAt = str.length() - scale;
277+
res << str.substr(0, decAt);
278+
279+
// Append any digits after the decimal.
280+
if (decAt < str.length()) {
281+
res << '.' << str.substr(decAt);
282+
}
283+
}
284+
285+
return res.str();
286+
}
287+
249288
}

clickhouse/columns/decimal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class ColumnDecimal : public Column {
3333
void Swap(Column& other) override;
3434
ItemView GetItem(size_t index) const override;
3535

36+
/// Returns a string representation of the Decimal value at \p index.
37+
std::string GetString(size_t index) const;
38+
3639
size_t GetScale() const;
3740
size_t GetPrecision() const;
3841

ut/client_ut.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <string_view>
2020
#include <thread>
2121
#include <chrono>
22+
#include <string>
23+
#include <list>
2224

2325
using namespace clickhouse;
2426

@@ -841,6 +843,9 @@ TEST_P(ClientCase, Decimal) {
841843
auto decimal = [&b](size_t column, size_t row) {
842844
return b[column]->As<ColumnDecimal>()->At(row);
843845
};
846+
auto dec_string = [&b](size_t column, size_t row) {
847+
return b[column]->As<ColumnDecimal>()->GetString(row);
848+
};
844849

845850
EXPECT_EQ(1u, b[0]->As<ColumnUInt64>()->At(0));
846851
EXPECT_EQ("123456789", int128_to_string(decimal(1, 0)));
@@ -849,6 +854,12 @@ TEST_P(ClientCase, Decimal) {
849854
EXPECT_EQ("123456789", int128_to_string(decimal(4, 0)));
850855
EXPECT_EQ("123456789012345678", int128_to_string(decimal(5, 0)));
851856
EXPECT_EQ("1234567890123456789", int128_to_string(decimal(6, 0)));
857+
EXPECT_EQ("12345.6789", dec_string(1, 0));
858+
EXPECT_EQ("123456789.012345678", dec_string(2, 0));
859+
EXPECT_EQ("0.1234567890123456789", dec_string(3, 0));
860+
EXPECT_EQ("12345.6789", dec_string(4, 0));
861+
EXPECT_EQ("123456789.012345678", dec_string(5, 0));
862+
EXPECT_EQ("0.1234567890123456789", dec_string(6, 0));
852863

853864
EXPECT_EQ(2u, b[0]->As<ColumnUInt64>()->At(1));
854865
EXPECT_EQ("999999999", int128_to_string(decimal(1, 1)));
@@ -857,6 +868,12 @@ TEST_P(ClientCase, Decimal) {
857868
EXPECT_EQ("999999999", int128_to_string(decimal(4, 1)));
858869
EXPECT_EQ("999999999999999999", int128_to_string(decimal(5, 1)));
859870
EXPECT_EQ("999999999999999999", int128_to_string(decimal(6, 1)));
871+
EXPECT_EQ("99999.9999", dec_string(1, 1));
872+
EXPECT_EQ("999999999.999999999", dec_string(2, 1));
873+
EXPECT_EQ("0.0999999999999999999", dec_string(3, 1));
874+
EXPECT_EQ("99999.9999", dec_string(4, 1));
875+
EXPECT_EQ("999999999.999999999", dec_string(5, 1));
876+
EXPECT_EQ("0.0999999999999999999", dec_string(6, 1));
860877

861878
EXPECT_EQ(3u, b[0]->As<ColumnUInt64>()->At(2));
862879
EXPECT_EQ("-999999999", int128_to_string(decimal(1, 2)));
@@ -865,6 +882,12 @@ TEST_P(ClientCase, Decimal) {
865882
EXPECT_EQ("-999999999", int128_to_string(decimal(4, 2)));
866883
EXPECT_EQ("-999999999999999999", int128_to_string(decimal(5, 2)));
867884
EXPECT_EQ("-999999999999999999", int128_to_string(decimal(6, 2)));
885+
EXPECT_EQ("-99999.9999", dec_string(1, 2));
886+
EXPECT_EQ("-999999999.999999999", dec_string(2, 2));
887+
EXPECT_EQ("-0.0999999999999999999", dec_string(3, 2));
888+
EXPECT_EQ("-99999.9999", dec_string(4, 2));
889+
EXPECT_EQ("-999999999.999999999", dec_string(5, 2));
890+
EXPECT_EQ("-0.0999999999999999999", dec_string(6, 2));
868891

869892
EXPECT_EQ(4u, b[0]->As<ColumnUInt64>()->At(3));
870893
EXPECT_EQ("123456789", int128_to_string(decimal(1, 3)));
@@ -873,6 +896,12 @@ TEST_P(ClientCase, Decimal) {
873896
EXPECT_EQ("123456789", int128_to_string(decimal(4, 3)));
874897
EXPECT_EQ("123456789012345678", int128_to_string(decimal(5, 3)));
875898
EXPECT_EQ("12345678901234567890123456789012345678", int128_to_string(decimal(6, 3)));
899+
EXPECT_EQ("12345.6789", dec_string(1, 3));
900+
EXPECT_EQ("123456789.012345678", dec_string(2, 3));
901+
EXPECT_EQ("1234567890123456789.0123456789012345678", dec_string(3, 3));
902+
EXPECT_EQ("12345.6789", dec_string(4, 3));
903+
EXPECT_EQ("123456789.012345678", dec_string(5, 3));
904+
EXPECT_EQ("1234567890123456789.0123456789012345678", dec_string(6, 3));
876905

877906
EXPECT_EQ(5u, b[0]->As<ColumnUInt64>()->At(4));
878907
EXPECT_EQ("-123456789", int128_to_string(decimal(1, 4)));
@@ -881,6 +910,12 @@ TEST_P(ClientCase, Decimal) {
881910
EXPECT_EQ("-123456789", int128_to_string(decimal(4, 4)));
882911
EXPECT_EQ("-123456789012345678", int128_to_string(decimal(5, 4)));
883912
EXPECT_EQ("-12345678901234567890123456789012345678", int128_to_string(decimal(6, 4)));
913+
EXPECT_EQ("-12345.6789", dec_string(1, 4));
914+
EXPECT_EQ("-123456789.012345678", dec_string(2, 4));
915+
EXPECT_EQ("-1234567890123456789.0123456789012345678", dec_string(3, 4));
916+
EXPECT_EQ("-12345.6789", dec_string(4, 4));
917+
EXPECT_EQ("-123456789.012345678", dec_string(5, 4));
918+
EXPECT_EQ("-1234567890123456789.0123456789012345678", dec_string(6, 4));
884919

885920
EXPECT_EQ(6u, b[0]->As<ColumnUInt64>()->At(5));
886921
EXPECT_EQ("123456780", int128_to_string(decimal(1, 5)));
@@ -889,9 +924,75 @@ TEST_P(ClientCase, Decimal) {
889924
EXPECT_EQ("123456789", int128_to_string(decimal(4, 5)));
890925
EXPECT_EQ("123456789012345678", int128_to_string(decimal(5, 5)));
891926
EXPECT_EQ("12345678901234567890123456789012345678", int128_to_string(decimal(6, 5)));
927+
EXPECT_EQ("12345.6780", dec_string(1, 5));
928+
EXPECT_EQ("123456789.012345678", dec_string(2, 5));
929+
EXPECT_EQ("1234567890123456789.0123456789012345678", dec_string(3, 5));
930+
EXPECT_EQ("12345.6789", dec_string(4, 5));
931+
EXPECT_EQ("123456789.012345678", dec_string(5, 5));
932+
EXPECT_EQ("1234567890123456789.0123456789012345678", dec_string(6, 5));
892933
});
893934
}
894935

936+
TEST_P(ClientCase, DecimalString) {
937+
struct testCase {
938+
int64_t input;
939+
std::vector<std::string> exp;
940+
};
941+
942+
auto columns = std::vector<std::shared_ptr<ColumnDecimal>> {
943+
std::make_shared<ColumnDecimal>(8, 0),
944+
std::make_shared<ColumnDecimal>(8, 2),
945+
std::make_shared<ColumnDecimal>(8, 4),
946+
std::make_shared<ColumnDecimal>(8, 6),
947+
std::make_shared<ColumnDecimal>(8, 8),
948+
};
949+
950+
for (auto const& tc : std::list<testCase> {
951+
testCase{
952+
1,
953+
{"1", "0.01", "0.0001", "0.000001", "0.00000001"},
954+
},
955+
testCase{
956+
64,
957+
{"64", "0.64", "0.0064", "0.000064", "0.00000064"},
958+
},
959+
testCase{
960+
128,
961+
{"128", "1.28", "0.0128", "0.000128", "0.00000128"},
962+
},
963+
testCase{
964+
1024,
965+
{"1024", "10.24", "0.1024", "0.001024", "0.00001024"},
966+
},
967+
testCase{
968+
87654,
969+
{"87654", "876.54", "8.7654", "0.087654", "0.00087654"},
970+
},
971+
testCase{
972+
918273,
973+
{"918273", "9182.73", "91.8273", "0.918273", "0.00918273"},
974+
},
975+
testCase{
976+
23456789,
977+
{"23456789", "234567.89", "2345.6789", "23.456789", "0.23456789"},
978+
},
979+
testCase{
980+
1234567890,
981+
{"1234567890", "12345678.90", "123456.7890", "1234.567890", "12.34567890"},
982+
},
983+
}) {
984+
for (size_t i = 0; i < tc.exp.size(); i++) {
985+
auto col = columns[i];
986+
col->Append(tc.input);
987+
EXPECT_EQ(tc.exp[i], col->GetString(0));
988+
col->Clear();
989+
col->Append(-tc.input);
990+
EXPECT_EQ("-"+tc.exp[i], col->GetString(0));
991+
col->Clear();
992+
}
993+
}
994+
}
995+
895996
// Test special chars in names
896997
TEST_P(ClientCase, ColEscapeNameTest) {
897998
client_->Execute(R"sql(DROP TEMPORARY TABLE IF EXISTS "test_clickhouse_cpp_col_escape_""name_test";)sql");

0 commit comments

Comments
 (0)