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