1#include <DataTypes/DataTypeString.h>
2#include <Columns/ColumnString.h>
3#include <Columns/ColumnFixedString.h>
4#include <Columns/ColumnArray.h>
5#include <Functions/FunctionFactory.h>
6#include <Functions/FunctionHelpers.h>
7#include <ext/map.h>
8
9
10namespace DB
11{
12
13namespace ErrorCodes
14{
15 extern const int ILLEGAL_COLUMN;
16 extern const int ILLEGAL_TYPE_OF_ARGUMENT;
17}
18
19
20/** Reverse the string as a sequence of bytes.
21 */
22struct ReverseImpl
23{
24 static void vector(const ColumnString::Chars & data,
25 const ColumnString::Offsets & offsets,
26 ColumnString::Chars & res_data,
27 ColumnString::Offsets & res_offsets)
28 {
29 res_data.resize(data.size());
30 res_offsets.assign(offsets);
31 size_t size = offsets.size();
32
33 ColumnString::Offset prev_offset = 0;
34 for (size_t i = 0; i < size; ++i)
35 {
36 for (size_t j = prev_offset; j < offsets[i] - 1; ++j)
37 res_data[j] = data[offsets[i] + prev_offset - 2 - j];
38 res_data[offsets[i] - 1] = 0;
39 prev_offset = offsets[i];
40 }
41 }
42
43 static void vector_fixed(const ColumnString::Chars & data, size_t n, ColumnString::Chars & res_data)
44 {
45 res_data.resize(data.size());
46 size_t size = data.size() / n;
47
48 for (size_t i = 0; i < size; ++i)
49 for (size_t j = i * n; j < (i + 1) * n; ++j)
50 res_data[j] = data[(i * 2 + 1) * n - j - 1];
51 }
52};
53
54
55class FunctionReverse : public IFunction
56{
57public:
58 static constexpr auto name = "reverse";
59 static FunctionPtr create(const Context &)
60 {
61 return std::make_shared<FunctionReverse>();
62 }
63
64 String getName() const override
65 {
66 return name;
67 }
68
69 size_t getNumberOfArguments() const override
70 {
71 return 1;
72 }
73
74 bool isInjective(const Block &) override
75 {
76 return true;
77 }
78
79 DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
80 {
81 if (!isStringOrFixedString(arguments[0])
82 && !isArray(arguments[0]))
83 throw Exception(
84 "Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
85
86 return arguments[0];
87 }
88
89 bool useDefaultImplementationForConstants() const override { return true; }
90
91 void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t) override
92 {
93 const ColumnPtr column = block.getByPosition(arguments[0]).column;
94 if (const ColumnString * col = checkAndGetColumn<ColumnString>(column.get()))
95 {
96 auto col_res = ColumnString::create();
97 ReverseImpl::vector(col->getChars(), col->getOffsets(), col_res->getChars(), col_res->getOffsets());
98 block.getByPosition(result).column = std::move(col_res);
99 }
100 else if (const ColumnFixedString * col_fixed = checkAndGetColumn<ColumnFixedString>(column.get()))
101 {
102 auto col_res = ColumnFixedString::create(col_fixed->getN());
103 ReverseImpl::vector_fixed(col_fixed->getChars(), col_fixed->getN(), col_res->getChars());
104 block.getByPosition(result).column = std::move(col_res);
105 }
106 else
107 throw Exception(
108 "Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of argument of function " + getName(),
109 ErrorCodes::ILLEGAL_COLUMN);
110 }
111};
112
113
114/// Also works with arrays.
115class ReverseOverloadResolver : public IFunctionOverloadResolverImpl
116{
117public:
118 static constexpr auto name = "reverse";
119 static FunctionOverloadResolverImplPtr create(const Context & context) { return std::make_unique<ReverseOverloadResolver>(context); }
120
121 explicit ReverseOverloadResolver(const Context & context_) : context(context_) {}
122
123 String getName() const override { return name; }
124 size_t getNumberOfArguments() const override { return 1; }
125
126 FunctionBaseImplPtr build(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type) const override
127 {
128 if (isArray(arguments.at(0).type))
129 return FunctionOverloadResolverAdaptor(FunctionFactory::instance().getImpl("arrayReverse", context)).buildImpl(arguments);
130 else
131 return std::make_unique<DefaultFunction>(
132 FunctionReverse::create(context),
133 ext::map<DataTypes>(arguments, [](const auto & elem) { return elem.type; }),
134 return_type);
135 }
136
137 DataTypePtr getReturnType(const DataTypes & arguments) const override
138 {
139 return arguments.at(0);
140 }
141
142private:
143 const Context & context;
144};
145
146
147void registerFunctionReverse(FunctionFactory & factory)
148{
149 factory.registerFunction<ReverseOverloadResolver>(FunctionFactory::CaseInsensitive);
150}
151
152}
153