| 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 | |
| 10 | namespace DB |
| 11 | { |
| 12 | |
| 13 | namespace 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 | */ |
| 22 | struct 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 | |
| 55 | class FunctionReverse : public IFunction |
| 56 | { |
| 57 | public: |
| 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. |
| 115 | class ReverseOverloadResolver : public IFunctionOverloadResolverImpl |
| 116 | { |
| 117 | public: |
| 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 | |
| 142 | private: |
| 143 | const Context & context; |
| 144 | }; |
| 145 | |
| 146 | |
| 147 | void registerFunctionReverse(FunctionFactory & factory) |
| 148 | { |
| 149 | factory.registerFunction<ReverseOverloadResolver>(FunctionFactory::CaseInsensitive); |
| 150 | } |
| 151 | |
| 152 | } |
| 153 | |