1#include <Functions/FunctionFactory.h>
2#include <Functions/FunctionsStringSearch.h>
3#include <common/find_symbols.h>
4
5namespace DB
6{
7
8struct ExtractURLParameterImpl
9{
10 static void vector(const ColumnString::Chars & data,
11 const ColumnString::Offsets & offsets,
12 std::string pattern,
13 ColumnString::Chars & res_data, ColumnString::Offsets & res_offsets)
14 {
15 res_data.reserve(data.size() / 5);
16 res_offsets.resize(offsets.size());
17
18 pattern += '=';
19 const char * param_str = pattern.c_str();
20 size_t param_len = pattern.size();
21
22 ColumnString::Offset prev_offset = 0;
23 ColumnString::Offset res_offset = 0;
24
25 for (size_t i = 0; i < offsets.size(); ++i)
26 {
27 ColumnString::Offset cur_offset = offsets[i];
28
29 const char * str = reinterpret_cast<const char *>(&data[prev_offset]);
30 const char * end = reinterpret_cast<const char *>(&data[cur_offset]);
31
32 /// Find query string or fragment identifier.
33 /// Note that we support parameters in fragment identifier in the same way as in query string.
34
35 const char * const query_string_begin = find_first_symbols<'?', '#'>(str, end);
36
37 /// Will point to the beginning of "name=value" pair. Then it will be reassigned to the beginning of "value".
38 const char * param_begin = nullptr;
39
40 if (query_string_begin + 1 < end)
41 {
42 param_begin = query_string_begin + 1;
43
44 while (true)
45 {
46 param_begin = static_cast<const char *>(memmem(param_begin, end - param_begin, param_str, param_len));
47
48 if (!param_begin)
49 break;
50
51 if (param_begin[-1] != '?' && param_begin[-1] != '#' && param_begin[-1] != '&')
52 {
53 /// Parameter name is different but has the same suffix.
54 param_begin += param_len;
55 continue;
56 }
57 else
58 {
59 param_begin += param_len;
60 break;
61 }
62 }
63 }
64
65 if (param_begin)
66 {
67 const char * param_end = find_first_symbols<'&', '#'>(param_begin, end);
68 if (param_end == end)
69 param_end = param_begin + strlen(param_begin);
70
71 size_t param_size = param_end - param_begin;
72
73 res_data.resize(res_offset + param_size + 1);
74 memcpySmallAllowReadWriteOverflow15(&res_data[res_offset], param_begin, param_size);
75 res_offset += param_size;
76 }
77 else
78 {
79 /// No parameter found, put empty string in result.
80 res_data.resize(res_offset + 1);
81 }
82
83 res_data[res_offset] = 0;
84 ++res_offset;
85 res_offsets[i] = res_offset;
86
87 prev_offset = cur_offset;
88 }
89 }
90};
91
92struct NameExtractURLParameter { static constexpr auto name = "extractURLParameter"; };
93using FunctionExtractURLParameter = FunctionsStringSearchToString<ExtractURLParameterImpl, NameExtractURLParameter>;
94
95void registerFunctionExtractURLParameter(FunctionFactory & factory)
96{
97 factory.registerFunction<FunctionExtractURLParameter>();
98}
99
100}
101