From 8686c3150c5a36e256b2fffc976a8a45e44d15a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Wed, 26 Jul 2023 13:37:02 +0000 Subject: [PATCH] Support for DECIMAL in Clickhouse --- lib/ClickHouse_Server.cpp | 49 ++++++++++++++++++++- test/tap/tests/test_clickhouse_server-t.cpp | 2 + 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/ClickHouse_Server.cpp b/lib/ClickHouse_Server.cpp index 7c53e31c7..32ebb7e2f 100644 --- a/lib/ClickHouse_Server.cpp +++ b/lib/ClickHouse_Server.cpp @@ -62,6 +62,36 @@ using namespace clickhouse; +std::string dec128_to_pchar(Int128 value, size_t scale) { +// code borrowed from https://github.com/bderleta/php-clickhouse/blob/master/conversions.h + bool sign = (value < 0); + char buffer48[48]; + char* s = &buffer48[47]; + size_t w = 0; + *(--s) = 0; + if (sign) + value = -value; + while (value) { + Int128 v = value; + v %= 10; + char c = (char)v; + *(--s) = c + '0'; + if ((++w) == scale) + *(--s) = '.'; + value /= 10; + } + while (w < scale) { + *(--s) = '0'; + if ((++w) == scale) + *(--s) = '.'; + } + if (w == scale) + *(--s) = '0'; + if (sign) + *(--s) = '-'; + return std::string(s); +} + __thread MySQL_Session * clickhouse_thread___mysql_sess; inline void ClickHouse_to_MySQL(const Block& block) { @@ -99,7 +129,7 @@ inline void ClickHouse_to_MySQL(const Block& block) { #endif // CXX17 } - if (cc >= clickhouse::Type::Code::Int8 && cc <= clickhouse::Type::Code::Float64) { + if (cc >= clickhouse::Type::Code::Int8 && cc <= clickhouse::Type::Code::Decimal128) { bool _unsigned = false; uint16_t flags = is_null | 128; @@ -151,6 +181,14 @@ inline void ClickHouse_to_MySQL(const Block& block) { size = 22; decimals = 31; break; + case clickhouse::Type::Code::Decimal: + case clickhouse::Type::Code::Decimal32: + case clickhouse::Type::Code::Decimal64: + case clickhouse::Type::Code::Decimal128: + type = MYSQL_TYPE_NEWDECIMAL; + size = 32; + decimals = 31; + break; default: _unsigned = false; flags = 128; @@ -237,6 +275,15 @@ inline void ClickHouse_to_MySQL(const Block& block) { case clickhouse::Type::Code::Float64: s=std::to_string(block[i]->As()->At(r)); break; + case clickhouse::Type::Code::Decimal: + case clickhouse::Type::Code::Decimal32: + case clickhouse::Type::Code::Decimal64: + case clickhouse::Type::Code::Decimal128: + { + size_t scale = block[i]->Type()->As()->GetScale(); + s = dec128_to_pchar(block[i]->As()->At(r), scale); + } + break; case clickhouse::Type::Code::Enum8: s=block[i]->As()->NameAt(r);; break; diff --git a/test/tap/tests/test_clickhouse_server-t.cpp b/test/tap/tests/test_clickhouse_server-t.cpp index 6f7028880..f844c1e39 100644 --- a/test/tap/tests/test_clickhouse_server-t.cpp +++ b/test/tap/tests/test_clickhouse_server-t.cpp @@ -253,6 +253,8 @@ std::vector queries_set1 { std::make_tuple("SELECT NULL AS a", 0, 1), std::make_tuple("SELECT NULL+2 AS a, 'hello', NULL+1, 'world', NULL AS b", 0, 1), std::make_tuple("SELECT CONCAT('AAA',NULL)", 0, 1), + std::make_tuple("SELECT CAST(-1234.1234, 'Decimal32(3)')", 0, 1), + std::make_tuple("SELECT CAST(1000.0, 'Decimal128(3)')", 0, 1), std::make_tuple("DROP TABLE IF EXISTS table1", 0, -1), std::make_tuple("CREATE TABLE table1 (CounterID INT, EventDate DATE, col1 INT) ENGINE=MergeTree(EventDate, (CounterID, EventDate), 8192)", 0, -1), std::make_tuple("CREATE TABLE table1 (CounterID INT, EventDate DATE, col1 INT) ENGINE=MergeTree(EventDate, (CounterID, EventDate), 8192)", 1148, -1), // the second time it must fails