Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decimal hex function #7355

Merged
merged 24 commits into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 50 additions & 25 deletions dbms/src/Functions/FunctionsCoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <Columns/ColumnArray.h>
#include <Columns/ColumnConst.h>
#include <Columns/ColumnTuple.h>
#include <Columns/ColumnDecimal.h>
#include <Functions/IFunction.h>
#include <Functions/FunctionHelpers.h>

Expand Down Expand Up @@ -949,7 +950,8 @@ class FunctionHex : public IFunction
if (!which.isStringOrFixedString() &&
!which.isDateOrDateTime() &&
!which.isUInt() &&
!which.isFloat())
!which.isFloat() &&
!which.isDecimal())
throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);

Expand Down Expand Up @@ -1023,36 +1025,55 @@ class FunctionHex : public IFunction
}

template <typename T>
bool tryExecuteFloat(const IColumn * col, ColumnPtr & col_res)
void executeFloatAndDecimal(const T & in_vec, ColumnPtr & col_res, const size_t type_size_in_bytes)
{
const ColumnVector<T> * col_vec = checkAndGetColumn<ColumnVector<T>>(col);
const size_t hex_length = type_size_in_bytes * 2 + 1; /// Including trailing zero byte.
auto col_str = ColumnString::create();

static constexpr size_t FLOAT_HEX_LENGTH = sizeof(T) * 2 + 1; /// Including trailing zero byte.
ColumnString::Chars & out_vec = col_str->getChars();
ColumnString::Offsets & out_offsets = col_str->getOffsets();

if (col_vec)
{
auto col_str = ColumnString::create();
ColumnString::Chars & out_vec = col_str->getChars();
ColumnString::Offsets & out_offsets = col_str->getOffsets();
size_t size = in_vec.size();
out_offsets.resize(size);
out_vec.resize(size * hex_length);

const typename ColumnVector<T>::Container & in_vec = col_vec->getData();

size_t size = in_vec.size();
out_offsets.resize(size);
out_vec.resize(size * FLOAT_HEX_LENGTH);
size_t pos = 0;
char * out = reinterpret_cast<char *>(&out_vec[0]);
for (size_t i = 0; i < size; ++i)
{
const UInt8 * in_pos = reinterpret_cast<const UInt8 *>(&in_vec[i]);
executeOneString(in_pos, in_pos + type_size_in_bytes, out);

size_t pos = 0;
char * out = reinterpret_cast<char *>(&out_vec[0]);
for (size_t i = 0; i < size; ++i)
{
const UInt8 * in_pos = reinterpret_cast<const UInt8 *>(&in_vec[i]);
executeOneString(in_pos, in_pos + sizeof(T), out);
pos += hex_length;
out_offsets[i] = pos;
}
col_res = std::move(col_str);
}

pos += FLOAT_HEX_LENGTH;
out_offsets[i] = pos;
}
template <typename T>
bool tryExecuteFloat(const IColumn * col, ColumnPtr & col_res)
{
const ColumnVector<T> * col_vec = checkAndGetColumn<ColumnVector<T>>(col);
if (col_vec)
{
const typename ColumnVector<T>::Container & in_vec = col_vec->getData();
executeFloatAndDecimal<typename ColumnVector<T>::Container>(in_vec, col_res, sizeof(T));
return true;
}
else
{
return false;
}
}

col_res = std::move(col_str);
template <typename T>
bool tryExecuteDecimal(const IColumn * col, ColumnPtr & col_res)
{
const ColumnDecimal<T> * col_dec = checkAndGetColumn<ColumnDecimal<T>>(col);
if (col_dec)
{
const typename ColumnDecimal<T>::Container & in_vec = col_dec->getData();
executeFloatAndDecimal<typename ColumnDecimal<T>::Container>(in_vec, col_res, sizeof(T));
return true;
}
else
Expand All @@ -1061,6 +1082,7 @@ class FunctionHex : public IFunction
}
}


void executeOneString(const UInt8 * pos, const UInt8 * end, char *& out)
{
while (pos < end)
Expand Down Expand Up @@ -1177,7 +1199,10 @@ class FunctionHex : public IFunction
tryExecuteString(column, res_column) ||
tryExecuteFixedString(column, res_column) ||
tryExecuteFloat<Float32>(column, res_column) ||
tryExecuteFloat<Float64>(column, res_column))
tryExecuteFloat<Float64>(column, res_column) ||
tryExecuteDecimal<Decimal32>(column, res_column) ||
tryExecuteDecimal<Decimal64>(column, res_column) ||
tryExecuteDecimal<Decimal128>(column, res_column))
return;

throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
Expand Down
11 changes: 11 additions & 0 deletions dbms/tests/queries/0_stateless/01013_hex_decimal.reference
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
64000000
64000000
42020000
B61BFEFFFFFFFFFF
EF260000000000000000000000000000
400D0300
28110300
403A340100000000
E0C0350100000000
00B08EF01B0000000000000000000000
007A292C1C0000000000000000000000
8 changes: 8 additions & 0 deletions dbms/tests/queries/0_stateless/01013_hex_decimal.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
SELECT hex(toDecimal32(1.0, 2));
SELECT hex(toDecimal32(1., 2));
SELECT hex(toDecimal32(0.000578, 6));
SELECT hex(toDecimal64(-123.978, 3));
SELECT hex(toDecimal128(99.67, 2));
SELECT hex(toDecimal32(number, 3)) FROM numbers(200, 2);
SELECT hex(toDecimal64(number, 5)) FROM numbers(202, 2);
SELECT hex(toDecimal128(number, 9)) FROM numbers(120, 2);
2 changes: 1 addition & 1 deletion docs/en/query_language/functions/encoding_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Accepts multiple arguments of numberic types. Returns a string with the length a

## hex

Accepts arguments of types: `String`, `unsigned integer`, `Date`, or `DateTime`. Returns a string containing the argument's hexadecimal representation. Uses uppercase letters `A-F`. Does not use `0x` prefixes or `h` suffixes. For strings, all bytes are simply encoded as two hexadecimal numbers. Numbers are converted to big endian ("human readable") format. For numbers, older zeros are trimmed, but only by entire bytes. For example, `hex (1) = '01'`. `Date` is encoded as the number of days since the beginning of the Unix epoch. `DateTime` is encoded as the number of seconds since the beginning of the Unix epoch.
Accepts arguments of types: `String`, `unsigned integer`, `float`, `decimal`, `Date`, or `DateTime`. Returns a string containing the argument's hexadecimal representation. Uses uppercase letters `A-F`. Does not use `0x` prefixes or `h` suffixes. For strings, all bytes are simply encoded as two hexadecimal numbers. Numbers are converted to big endian ("human readable") format. For numbers, older zeros are trimmed, but only by entire bytes. For example, `hex (1) = '01'`. `Date` is encoded as the number of days since the beginning of the Unix epoch. `DateTime` is encoded as the number of seconds since the beginning of the Unix epoch. `float` and `decimal` is encoded as their hexadecimal representation in memory.

## unhex(str)

Expand Down
2 changes: 1 addition & 1 deletion docs/ru/query_language/functions/encoding_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## hex

Принимает аргументы типов: `String`, `unsigned integer`, `Date`, or `DateTime`. Возвращает строку, содержащую шестнадцатеричное представление аргумента. Используются заглавные буквы `A-F`. Не используются префиксы `0x` и суффиксы `h`. Для строк просто все байты кодируются в виде двух шестнадцатеричных цифр. Числа выводятся в big endian ("человеческом") формате. Для чисел вырезаются старшие нули, но только по целым байтам. Например, `hex(1) = '01'`. `Date` кодируется как число дней с начала unix-эпохи. `DateTime` кодируются как число секунд с начала unix-эпохи.
Принимает аргументы типов: `String`, `unsigned integer`, `float`, `decimal`, `Date`, or `DateTime`. Возвращает строку, содержащую шестнадцатеричное представление аргумента. Используются заглавные буквы `A-F`. Не используются префиксы `0x` и суффиксы `h`. Для строк просто все байты кодируются в виде двух шестнадцатеричных цифр. Числа выводятся в big endian ("человеческом") формате. Для чисел вырезаются старшие нули, но только по целым байтам. Например, `hex(1) = '01'`. `Date` кодируется как число дней с начала unix-эпохи. `DateTime` кодируются как число секунд с начала unix-эпохи. `float` и `decimal` кодируются как их шестнадцатеричное представление в памяти.

## unhex(str)
Принимает строку, содержащую произвольное количество шестнадцатеричных цифр, и возвращает строку, содержащую соответствующие байты. Поддерживаются как строчные, так и заглавные буквы A-F. Число шестнадцатеричных цифр не обязано быть чётным. Если оно нечётное - последняя цифра интерпретируется как младшая половинка байта 00-0F. Если строка-аргумент содержит что-либо кроме шестнадцатеричных цифр, то будет возвращён какой-либо implementation-defined результат (не кидается исключение).
Expand Down