ClickHouse
137 строк · 4.6 Кб
1#include <Functions/IFunction.h>2#include <Functions/FunctionFactory.h>3#include <Functions/FunctionHelpers.h>4#include <DataTypes/IDataType.h>5#include <DataTypes/DataTypeTuple.h>6#include <DataTypes/DataTypeArray.h>7#include <DataTypes/DataTypeString.h>8#include <Columns/ColumnTuple.h>9#include <Columns/ColumnArray.h>10#include <Columns/ColumnString.h>11#include <Columns/ColumnsNumber.h>12#include <Common/assert_cast.h>13#include <memory>14
15namespace DB16{
17namespace ErrorCodes18{
19extern const int ILLEGAL_TYPE_OF_ARGUMENT;20}
21
22namespace
23{
24
25/** Transform a named tuple into an array of pairs, where the first element
26* of the pair corresponds to the tuple field name and the second one to the
27* tuple value.
28*/
29class FunctionTupleToNameValuePairs : public IFunction30{
31public:32static constexpr auto name = "tupleToNameValuePairs";33static FunctionPtr create(ContextPtr)34{35return std::make_shared<FunctionTupleToNameValuePairs>();36}37
38String getName() const override39{40return name;41}42
43size_t getNumberOfArguments() const override44{45return 1;46}47
48bool useDefaultImplementationForConstants() const override49{50return true;51}52
53bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override54{55return true;56}57
58
59DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override60{61// get the type of all the fields in the tuple62const IDataType * col = arguments[0].type.get();63const DataTypeTuple * tuple = checkAndGetDataType<DataTypeTuple>(col);64
65if (!tuple)66throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,67"First argument for function {} must be a tuple.",68getName());69
70const auto & element_types = tuple->getElements();71
72if (element_types.empty())73throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,74"The argument tuple for function {} must not be empty.",75getName());76
77const auto & first_element_type = element_types[0];78
79bool all_value_types_equal = std::all_of(element_types.begin() + 1,80element_types.end(),81[&](const auto &other)82{83return first_element_type->equals(*other);84});85
86if (!all_value_types_equal)87{88throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,89"The argument tuple for function {} must contain just one type.",90getName());91}92
93DataTypePtr tuple_name_type = std::make_shared<DataTypeString>();94DataTypes item_data_types = {tuple_name_type,95first_element_type};96
97auto item_data_type = std::make_shared<DataTypeTuple>(item_data_types);98
99return std::make_shared<DataTypeArray>(item_data_type);100}101
102ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override103{104const IColumn * tuple_col = arguments[0].column.get();105const DataTypeTuple * tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].type.get());106const auto * tuple_col_concrete = assert_cast<const ColumnTuple*>(tuple_col);107
108auto keys = ColumnString::create();109MutableColumnPtr values = tuple_col_concrete->getColumn(0).cloneEmpty();110auto offsets = ColumnVector<UInt64>::create();111for (size_t row = 0; row < tuple_col_concrete->size(); ++row)112{113for (size_t col = 0; col < tuple_col_concrete->tupleSize(); ++col)114{115const std::string & key = tuple->getElementNames()[col];116const IColumn & value_column = tuple_col_concrete->getColumn(col);117
118values->insertFrom(value_column, row);119keys->insertData(key.data(), key.size());120}121offsets->insertValue(tuple_col_concrete->tupleSize() * (row + 1));122}123
124std::vector<ColumnPtr> tuple_columns = { std::move(keys), std::move(values) };125auto tuple_column = ColumnTuple::create(std::move(tuple_columns));126return ColumnArray::create(std::move(tuple_column), std::move(offsets));127}128};129
130}
131
132REGISTER_FUNCTION(TupleToNameValuePairs)133{
134factory.registerFunction<FunctionTupleToNameValuePairs>();135}
136
137}
138