ClickHouse
119 строк · 3.4 Кб
1#include <Columns/ColumnString.h>2#include <Functions/FunctionFactory.h>3#include <Functions/FunctionStringToString.h>4#include <base/find_symbols.h>5
6
7namespace DB8{
9namespace ErrorCodes10{
11extern const int ILLEGAL_TYPE_OF_ARGUMENT;12}
13
14namespace
15{
16
17struct TrimModeLeft18{
19static constexpr auto name = "trimLeft";20static constexpr bool trim_left = true;21static constexpr bool trim_right = false;22};23
24struct TrimModeRight25{
26static constexpr auto name = "trimRight";27static constexpr bool trim_left = false;28static constexpr bool trim_right = true;29};30
31struct TrimModeBoth32{
33static constexpr auto name = "trimBoth";34static constexpr bool trim_left = true;35static constexpr bool trim_right = true;36};37
38template <typename Mode>39class FunctionTrimImpl40{
41public:42static void vector(43const ColumnString::Chars & data,44const ColumnString::Offsets & offsets,45ColumnString::Chars & res_data,46ColumnString::Offsets & res_offsets)47{48size_t size = offsets.size();49res_offsets.resize(size);50res_data.reserve(data.size());51
52size_t prev_offset = 0;53size_t res_offset = 0;54
55const UInt8 * start;56size_t length;57
58for (size_t i = 0; i < size; ++i)59{60execute(reinterpret_cast<const UInt8 *>(&data[prev_offset]), offsets[i] - prev_offset - 1, start, length);61
62res_data.resize(res_data.size() + length + 1);63memcpySmallAllowReadWriteOverflow15(&res_data[res_offset], start, length);64res_offset += length + 1;65res_data[res_offset - 1] = '\0';66
67res_offsets[i] = res_offset;68prev_offset = offsets[i];69}70}71
72static void vectorFixed(const ColumnString::Chars &, size_t, ColumnString::Chars &)73{74throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Functions trimLeft, trimRight and trimBoth cannot work with FixedString argument");75}76
77private:78static void execute(const UInt8 * data, size_t size, const UInt8 *& res_data, size_t & res_size)79{80const char * char_data = reinterpret_cast<const char *>(data);81const char * char_end = char_data + size;82
83if constexpr (Mode::trim_left)84{ // NOLINT85const char * found = find_first_not_symbols<' '>(char_data, char_end);86size_t num_chars = found - char_data;87char_data += num_chars;88}89
90if constexpr (Mode::trim_right)91{ // NOLINT92const char * found = find_last_not_symbols_or_null<' '>(char_data, char_end);93if (found)94char_end = found + 1;95else96char_end = char_data;97}98
99res_data = reinterpret_cast<const UInt8 *>(char_data);100res_size = char_end - char_data;101}102};103
104using FunctionTrimLeft = FunctionStringToString<FunctionTrimImpl<TrimModeLeft>, TrimModeLeft>;105using FunctionTrimRight = FunctionStringToString<FunctionTrimImpl<TrimModeRight>, TrimModeRight>;106using FunctionTrimBoth = FunctionStringToString<FunctionTrimImpl<TrimModeBoth>, TrimModeBoth>;107
108}
109
110REGISTER_FUNCTION(Trim)111{
112factory.registerFunction<FunctionTrimLeft>();113factory.registerFunction<FunctionTrimRight>();114factory.registerFunction<FunctionTrimBoth>();115factory.registerAlias("ltrim", FunctionTrimLeft::name);116factory.registerAlias("rtrim", FunctionTrimRight::name);117factory.registerAlias("trim", FunctionTrimBoth::name);118}
119}
120