mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-30 11:32:03 +00:00
dbms: function 'transform': development [#METR-15987].
This commit is contained in:
parent
d371b7c843
commit
738e736500
@ -1000,31 +1000,23 @@ public:
|
|||||||
if (!array_from && !array_to)
|
if (!array_from && !array_to)
|
||||||
throw Exception("Second and third arguments of function " + getName() + " must be constant arrays.", ErrorCodes::ILLEGAL_COLUMN);
|
throw Exception("Second and third arguments of function " + getName() + " must be constant arrays.", ErrorCodes::ILLEGAL_COLUMN);
|
||||||
|
|
||||||
prepare(array_from->getData(), array_to->getData());
|
prepare(array_from->getData(), array_to->getData(), block, arguments);
|
||||||
|
|
||||||
/// Задано ли значение по-умолчанию.
|
|
||||||
Field default_value;
|
|
||||||
if (arguments.size() == 4)
|
|
||||||
{
|
|
||||||
const IColumnConst * default_col = dynamic_cast<const IColumnConst *>(&*block.getByPosition(arguments[3]).column);
|
|
||||||
default_value = (*default_col)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto in = block.getByPosition(arguments.front()).column.get();
|
const auto in = block.getByPosition(arguments.front()).column.get();
|
||||||
auto column_result = block.getByPosition(result).type->createColumn();
|
auto column_result = block.getByPosition(result).type->createColumn();
|
||||||
auto out = column_result.get();
|
auto out = column_result.get();
|
||||||
|
|
||||||
if (!executeNum<UInt8>(in, out, default_value)
|
if (!executeNum<UInt8>(in, out)
|
||||||
&& !executeNum<UInt16>(in, out, default_value)
|
&& !executeNum<UInt16>(in, out)
|
||||||
&& !executeNum<UInt32>(in, out, default_value)
|
&& !executeNum<UInt32>(in, out)
|
||||||
&& !executeNum<UInt64>(in, out, default_value)
|
&& !executeNum<UInt64>(in, out)
|
||||||
&& !executeNum<Int8>(in, out, default_value)
|
&& !executeNum<Int8>(in, out)
|
||||||
&& !executeNum<Int16>(in, out, default_value)
|
&& !executeNum<Int16>(in, out)
|
||||||
&& !executeNum<Int32>(in, out, default_value)
|
&& !executeNum<Int32>(in, out)
|
||||||
&& !executeNum<Int64>(in, out, default_value)
|
&& !executeNum<Int64>(in, out)
|
||||||
&& !executeNum<Float32>(in, out, default_value)
|
&& !executeNum<Float32>(in, out)
|
||||||
&& !executeNum<Float64>(in, out, default_value)
|
&& !executeNum<Float64>(in, out)
|
||||||
&& !executeString(in, out, default_value))
|
&& !executeString(in, out))
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Illegal column " + in->getName() + " of first argument of function " + getName(),
|
"Illegal column " + in->getName() + " of first argument of function " + getName(),
|
||||||
ErrorCodes::ILLEGAL_COLUMN);
|
ErrorCodes::ILLEGAL_COLUMN);
|
||||||
@ -1033,7 +1025,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool executeNum(const IColumn * in_untyped, IColumn * out_untyped, const Field & default_value)
|
bool executeNum(const IColumn * in_untyped, IColumn * out_untyped)
|
||||||
{
|
{
|
||||||
if (const auto in = typeid_cast<const ColumnVector<T> *>(in_untyped))
|
if (const auto in = typeid_cast<const ColumnVector<T> *>(in_untyped))
|
||||||
{
|
{
|
||||||
@ -1050,17 +1042,17 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!executeNumToNumWithDefault<T, UInt8>(in, out_untyped, default_value)
|
if (!executeNumToNumWithDefault<T, UInt8>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, UInt16>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, UInt16>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, UInt32>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, UInt32>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, UInt64>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, UInt64>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, Int8>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, Int8>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, Int16>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, Int16>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, Int32>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, Int32>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, Int64>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, Int64>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, Float32>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, Float32>(in, out_untyped)
|
||||||
&& !executeNumToNumWithDefault<T, Float64>(in, out_untyped, default_value)
|
&& !executeNumToNumWithDefault<T, Float64>(in, out_untyped)
|
||||||
&& !executeNumToString<T>(in, out_untyped, default_value))
|
&& !executeNumToString<T>(in, out_untyped))
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Illegal column " + in->getName() + " of elements of array of second argument of function " + getName(),
|
"Illegal column " + in->getName() + " of elements of array of second argument of function " + getName(),
|
||||||
ErrorCodes::ILLEGAL_COLUMN);
|
ErrorCodes::ILLEGAL_COLUMN);
|
||||||
@ -1078,21 +1070,21 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool executeString(const IColumn * in_untyped, IColumn * out_untyped, const Field & default_value)
|
bool executeString(const IColumn * in_untyped, IColumn * out_untyped)
|
||||||
{
|
{
|
||||||
if (const auto in = typeid_cast<const ColumnString *>(in_untyped))
|
if (const auto in = typeid_cast<const ColumnString *>(in_untyped))
|
||||||
{
|
{
|
||||||
if (!executeStringToNum<UInt8>(in, out_untyped, default_value)
|
if (!executeStringToNum<UInt8>(in, out_untyped)
|
||||||
&& !executeStringToNum<UInt16>(in, out_untyped, default_value)
|
&& !executeStringToNum<UInt16>(in, out_untyped)
|
||||||
&& !executeStringToNum<UInt32>(in, out_untyped, default_value)
|
&& !executeStringToNum<UInt32>(in, out_untyped)
|
||||||
&& !executeStringToNum<UInt64>(in, out_untyped, default_value)
|
&& !executeStringToNum<UInt64>(in, out_untyped)
|
||||||
&& !executeStringToNum<Int8>(in, out_untyped, default_value)
|
&& !executeStringToNum<Int8>(in, out_untyped)
|
||||||
&& !executeStringToNum<Int16>(in, out_untyped, default_value)
|
&& !executeStringToNum<Int16>(in, out_untyped)
|
||||||
&& !executeStringToNum<Int32>(in, out_untyped, default_value)
|
&& !executeStringToNum<Int32>(in, out_untyped)
|
||||||
&& !executeStringToNum<Int64>(in, out_untyped, default_value)
|
&& !executeStringToNum<Int64>(in, out_untyped)
|
||||||
&& !executeStringToNum<Float32>(in, out_untyped, default_value)
|
&& !executeStringToNum<Float32>(in, out_untyped)
|
||||||
&& !executeStringToNum<Float64>(in, out_untyped, default_value)
|
&& !executeStringToNum<Float64>(in, out_untyped)
|
||||||
&& !executeStringToString(in, out_untyped, default_value))
|
&& !executeStringToString(in, out_untyped))
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Illegal column " + in->getName() + " of elements of array of second argument of function " + getName(),
|
"Illegal column " + in->getName() + " of elements of array of second argument of function " + getName(),
|
||||||
ErrorCodes::ILLEGAL_COLUMN);
|
ErrorCodes::ILLEGAL_COLUMN);
|
||||||
@ -1110,7 +1102,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
bool executeNumToNumWithDefault(const ColumnVector<T> * in, IColumn * out_untyped, const Field & default_value)
|
bool executeNumToNumWithDefault(const ColumnVector<T> * in, IColumn * out_untyped)
|
||||||
{
|
{
|
||||||
auto out = typeid_cast<ColumnVector<U> *>(out_untyped);
|
auto out = typeid_cast<ColumnVector<U> *>(out_untyped);
|
||||||
if (!out)
|
if (!out)
|
||||||
@ -1121,7 +1113,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool executeNumToString(const ColumnVector<T> * in, IColumn * out_untyped, const Field & default_value)
|
bool executeNumToString(const ColumnVector<T> * in, IColumn * out_untyped)
|
||||||
{
|
{
|
||||||
auto out = typeid_cast<ColumnString *>(out_untyped);
|
auto out = typeid_cast<ColumnString *>(out_untyped);
|
||||||
if (!out)
|
if (!out)
|
||||||
@ -1134,7 +1126,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
bool executeStringToNum(const ColumnString * in, IColumn * out_untyped, const Field & default_value)
|
bool executeStringToNum(const ColumnString * in, IColumn * out_untyped)
|
||||||
{
|
{
|
||||||
auto out = typeid_cast<ColumnVector<U> *>(out_untyped);
|
auto out = typeid_cast<ColumnVector<U> *>(out_untyped);
|
||||||
if (!out)
|
if (!out)
|
||||||
@ -1144,7 +1136,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool executeStringToString(const ColumnString * in, IColumn * out_untyped, const Field & default_value)
|
bool executeStringToString(const ColumnString * in, IColumn * out_untyped)
|
||||||
{
|
{
|
||||||
auto out = typeid_cast<ColumnString *>(out_untyped);
|
auto out = typeid_cast<ColumnString *>(out_untyped);
|
||||||
if (!out)
|
if (!out)
|
||||||
@ -1275,11 +1267,13 @@ private:
|
|||||||
|
|
||||||
Arena string_pool;
|
Arena string_pool;
|
||||||
|
|
||||||
|
Field default_value; /// Null, если не задано.
|
||||||
|
|
||||||
bool prepared = false;
|
bool prepared = false;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
|
|
||||||
/// Может вызываться из разных потоков. Срабатывает только при первом вызове.
|
/// Может вызываться из разных потоков. Срабатывает только при первом вызове.
|
||||||
void prepare(const Array & from, const Array & to)
|
void prepare(const Array & from, const Array & to, Block & block, const ColumnNumbers & arguments)
|
||||||
{
|
{
|
||||||
if (prepared)
|
if (prepared)
|
||||||
return;
|
return;
|
||||||
@ -1296,6 +1290,30 @@ private:
|
|||||||
if (from.size() != to.size())
|
if (from.size() != to.size())
|
||||||
throw Exception("Second and third arguments of function " + getName() + " must be arrays of same size", ErrorCodes::BAD_ARGUMENTS);
|
throw Exception("Second and third arguments of function " + getName() + " must be arrays of same size", ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
Array converted_to;
|
||||||
|
const Array * used_to = &to;
|
||||||
|
|
||||||
|
/// Задано ли значение по-умолчанию.
|
||||||
|
|
||||||
|
if (arguments.size() == 4)
|
||||||
|
{
|
||||||
|
const IColumnConst * default_col = dynamic_cast<const IColumnConst *>(&*block.getByPosition(arguments[3]).column);
|
||||||
|
default_value = (*default_col)[0];
|
||||||
|
|
||||||
|
/// Нужно ли преобразовать элементы to и default_value к наименьшему общему типу, который является Float64?
|
||||||
|
if (default_value.getType() == Field::Types::Float64 && to[0].getType() != Field::Types::Float64)
|
||||||
|
{
|
||||||
|
converted_to.resize(to.size());
|
||||||
|
for (size_t i = 0, size = to.size(); i < size; ++i)
|
||||||
|
converted_to[i] = apply_visitor(FieldVisitorConvertToNumber<Float64>(), to[i]);
|
||||||
|
used_to = &converted_to;
|
||||||
|
}
|
||||||
|
else if (default_value.getType() != Field::Types::Float64 && to[0].getType() == Field::Types::Float64)
|
||||||
|
{
|
||||||
|
default_value = apply_visitor(FieldVisitorConvertToNumber<Float64>(), default_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Замечание: не делается проверка дубликатов в массиве from.
|
/// Замечание: не делается проверка дубликатов в массиве from.
|
||||||
|
|
||||||
if (from[0].getType() != Field::Types::String && to[0].getType() != Field::Types::String)
|
if (from[0].getType() != Field::Types::String && to[0].getType() != Field::Types::String)
|
||||||
@ -1303,7 +1321,7 @@ private:
|
|||||||
table_num_to_num.reset(new NumToNum);
|
table_num_to_num.reset(new NumToNum);
|
||||||
auto & table = *table_num_to_num;
|
auto & table = *table_num_to_num;
|
||||||
for (size_t i = 0; i < size; ++i)
|
for (size_t i = 0; i < size; ++i)
|
||||||
table[from[i].get<UInt64>()] = to[i].get<UInt64>();
|
table[from[i].get<UInt64>()] = (*used_to)[i].get<UInt64>();
|
||||||
}
|
}
|
||||||
else if (from[0].getType() != Field::Types::String && to[0].getType() == Field::Types::String)
|
else if (from[0].getType() != Field::Types::String && to[0].getType() == Field::Types::String)
|
||||||
{
|
{
|
||||||
@ -1324,7 +1342,7 @@ private:
|
|||||||
{
|
{
|
||||||
const String & str_from = from[i].get<const String &>();
|
const String & str_from = from[i].get<const String &>();
|
||||||
StringRef ref{string_pool.insert(str_from.data(), str_from.size() + 1), str_from.size() + 1};
|
StringRef ref{string_pool.insert(str_from.data(), str_from.size() + 1), str_from.size() + 1};
|
||||||
table[ref] = to[i].get<UInt64>();
|
table[ref] = (*used_to)[i].get<UInt64>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (from[0].getType() == Field::Types::String && to[0].getType() == Field::Types::String)
|
else if (from[0].getType() == Field::Types::String && to[0].getType() == Field::Types::String)
|
||||||
|
@ -68,3 +68,33 @@ abc
|
|||||||
333
|
333
|
||||||
0
|
0
|
||||||
0
|
0
|
||||||
|
-1
|
||||||
|
-1
|
||||||
|
-1
|
||||||
|
111
|
||||||
|
-1
|
||||||
|
222
|
||||||
|
-1
|
||||||
|
333
|
||||||
|
-1
|
||||||
|
-1
|
||||||
|
-1.1
|
||||||
|
-1.1
|
||||||
|
-1.1
|
||||||
|
111
|
||||||
|
-1.1
|
||||||
|
222
|
||||||
|
-1.1
|
||||||
|
333
|
||||||
|
-1.1
|
||||||
|
-1.1
|
||||||
|
1
|
||||||
|
1
|
||||||
|
1
|
||||||
|
111
|
||||||
|
1
|
||||||
|
222.2
|
||||||
|
1
|
||||||
|
333
|
||||||
|
1
|
||||||
|
1
|
||||||
|
@ -5,3 +5,6 @@ SELECT transform(toString(number), ['3', '5', '7'], ['hello', 'world', 'abc']) F
|
|||||||
SELECT transform(toString(number), ['3', '5', '7'], ['hello', 'world', 'abc'], '') FROM system.numbers LIMIT 10;
|
SELECT transform(toString(number), ['3', '5', '7'], ['hello', 'world', 'abc'], '') FROM system.numbers LIMIT 10;
|
||||||
SELECT transform(toString(number), ['3', '5', '7'], ['hello', 'world', 'abc'], '-') FROM system.numbers LIMIT 10;
|
SELECT transform(toString(number), ['3', '5', '7'], ['hello', 'world', 'abc'], '-') FROM system.numbers LIMIT 10;
|
||||||
SELECT transform(toString(number), ['3', '5', '7'], [111, 222, 333], 0) FROM system.numbers LIMIT 10;
|
SELECT transform(toString(number), ['3', '5', '7'], [111, 222, 333], 0) FROM system.numbers LIMIT 10;
|
||||||
|
SELECT transform(toString(number), ['3', '5', '7'], [111, 222, 333], -1) FROM system.numbers LIMIT 10;
|
||||||
|
SELECT transform(toString(number), ['3', '5', '7'], [111, 222, 333], -1.1) FROM system.numbers LIMIT 10;
|
||||||
|
SELECT transform(toString(number), ['3', '5', '7'], [111, 222.2, 333], 1) FROM system.numbers LIMIT 10;
|
||||||
|
Loading…
Reference in New Issue
Block a user