1 | #include <Parsers/ParserCreateQuotaQuery.h> |
2 | #include <Parsers/ASTCreateQuotaQuery.h> |
3 | #include <Parsers/CommonParsers.h> |
4 | #include <Parsers/parseIntervalKind.h> |
5 | #include <Parsers/parseIdentifierOrStringLiteral.h> |
6 | #include <Parsers/ParserRoleList.h> |
7 | #include <Parsers/ExpressionElementParsers.h> |
8 | #include <Parsers/ASTLiteral.h> |
9 | #include <Parsers/ASTRoleList.h> |
10 | #include <ext/range.h> |
11 | #include <boost/algorithm/string/predicate.hpp> |
12 | |
13 | |
14 | namespace DB |
15 | { |
16 | namespace ErrorCodes |
17 | { |
18 | extern const int SYNTAX_ERROR; |
19 | } |
20 | |
21 | |
22 | namespace |
23 | { |
24 | using KeyType = Quota::KeyType; |
25 | using ResourceType = Quota::ResourceType; |
26 | using ResourceAmount = Quota::ResourceAmount; |
27 | |
28 | bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name, bool alter) |
29 | { |
30 | return IParserBase::wrapParseImpl(pos, [&] |
31 | { |
32 | if (!new_name.empty() || !alter) |
33 | return false; |
34 | |
35 | if (!ParserKeyword{"RENAME TO" }.ignore(pos, expected)) |
36 | return false; |
37 | |
38 | return parseIdentifierOrStringLiteral(pos, expected, new_name); |
39 | }); |
40 | } |
41 | |
42 | bool parseKeyType(IParserBase::Pos & pos, Expected & expected, std::optional<Quota::KeyType> & key_type) |
43 | { |
44 | return IParserBase::wrapParseImpl(pos, [&] |
45 | { |
46 | if (key_type) |
47 | return false; |
48 | |
49 | if (!ParserKeyword{"KEYED BY" }.ignore(pos, expected)) |
50 | return false; |
51 | |
52 | ASTPtr key_type_ast; |
53 | if (!ParserStringLiteral().parse(pos, key_type_ast, expected)) |
54 | return false; |
55 | |
56 | const String & key_type_str = key_type_ast->as<ASTLiteral &>().value.safeGet<const String &>(); |
57 | for (auto kt : ext::range_with_static_cast<Quota::KeyType>(Quota::MAX_KEY_TYPE)) |
58 | if (boost::iequals(Quota::getNameOfKeyType(kt), key_type_str)) |
59 | { |
60 | key_type = kt; |
61 | return true; |
62 | } |
63 | |
64 | String all_key_types_str; |
65 | for (auto kt : ext::range_with_static_cast<Quota::KeyType>(Quota::MAX_KEY_TYPE)) |
66 | all_key_types_str += String(all_key_types_str.empty() ? "" : ", " ) + "'" + Quota::getNameOfKeyType(kt) + "'" ; |
67 | String msg = "Quota cannot be keyed by '" + key_type_str + "'. Expected one of these literals: " + all_key_types_str; |
68 | throw Exception(msg, ErrorCodes::SYNTAX_ERROR); |
69 | }); |
70 | } |
71 | |
72 | bool parseLimit(IParserBase::Pos & pos, Expected & expected, ResourceType & resource_type, ResourceAmount & max) |
73 | { |
74 | return IParserBase::wrapParseImpl(pos, [&] |
75 | { |
76 | if (!ParserKeyword{"MAX" }.ignore(pos, expected)) |
77 | return false; |
78 | |
79 | bool resource_type_set = false; |
80 | for (auto rt : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE)) |
81 | { |
82 | if (ParserKeyword{Quota::resourceTypeToKeyword(rt)}.ignore(pos, expected)) |
83 | { |
84 | resource_type = rt; |
85 | resource_type_set = true; |
86 | break; |
87 | } |
88 | } |
89 | if (!resource_type_set) |
90 | return false; |
91 | |
92 | if (!ParserToken{TokenType::Equals}.ignore(pos, expected)) |
93 | return false; |
94 | |
95 | ASTPtr max_ast; |
96 | if (ParserNumber{}.parse(pos, max_ast, expected)) |
97 | { |
98 | const Field & max_field = max_ast->as<ASTLiteral &>().value; |
99 | if (resource_type == Quota::EXECUTION_TIME) |
100 | max = Quota::secondsToExecutionTime(applyVisitor(FieldVisitorConvertToNumber<double>(), max_field)); |
101 | else |
102 | max = applyVisitor(FieldVisitorConvertToNumber<ResourceAmount>(), max_field); |
103 | } |
104 | else if (ParserKeyword{"ANY" }.ignore(pos, expected)) |
105 | { |
106 | max = Quota::UNLIMITED; |
107 | } |
108 | else |
109 | return false; |
110 | |
111 | return true; |
112 | }); |
113 | } |
114 | |
115 | bool parseCommaAndLimit(IParserBase::Pos & pos, Expected & expected, ResourceType & resource_type, ResourceAmount & max) |
116 | { |
117 | return IParserBase::wrapParseImpl(pos, [&] |
118 | { |
119 | if (!ParserToken{TokenType::Comma}.ignore(pos, expected)) |
120 | return false; |
121 | |
122 | return parseLimit(pos, expected, resource_type, max); |
123 | }); |
124 | } |
125 | |
126 | bool parseLimits(IParserBase::Pos & pos, Expected & expected, ASTCreateQuotaQuery::Limits & limits, bool alter) |
127 | { |
128 | return IParserBase::wrapParseImpl(pos, [&] |
129 | { |
130 | ASTCreateQuotaQuery::Limits new_limits; |
131 | if (!ParserKeyword{"FOR" }.ignore(pos, expected)) |
132 | return false; |
133 | |
134 | new_limits.randomize_interval = ParserKeyword{"RANDOMIZED" }.ignore(pos, expected); |
135 | |
136 | if (!ParserKeyword{"INTERVAL" }.ignore(pos, expected)) |
137 | return false; |
138 | |
139 | ASTPtr num_intervals_ast; |
140 | if (!ParserNumber{}.parse(pos, num_intervals_ast, expected)) |
141 | return false; |
142 | |
143 | double num_intervals = applyVisitor(FieldVisitorConvertToNumber<double>(), num_intervals_ast->as<ASTLiteral &>().value); |
144 | |
145 | IntervalKind interval_kind; |
146 | if (!parseIntervalKind(pos, expected, interval_kind)) |
147 | return false; |
148 | |
149 | new_limits.duration = std::chrono::seconds(static_cast<UInt64>(num_intervals * interval_kind.toAvgSeconds())); |
150 | |
151 | if (alter && ParserKeyword{"UNSET TRACKING" }.ignore(pos, expected)) |
152 | { |
153 | new_limits.unset_tracking = true; |
154 | } |
155 | else if (ParserKeyword{"SET TRACKING" }.ignore(pos, expected) || ParserKeyword{"TRACKING" }.ignore(pos, expected)) |
156 | { |
157 | } |
158 | else |
159 | { |
160 | ParserKeyword{"SET" }.ignore(pos, expected); |
161 | ResourceType resource_type; |
162 | ResourceAmount max; |
163 | if (!parseLimit(pos, expected, resource_type, max)) |
164 | return false; |
165 | |
166 | new_limits.max[resource_type] = max; |
167 | while (parseCommaAndLimit(pos, expected, resource_type, max)) |
168 | new_limits.max[resource_type] = max; |
169 | } |
170 | |
171 | limits = new_limits; |
172 | return true; |
173 | }); |
174 | } |
175 | |
176 | bool parseAllLimits(IParserBase::Pos & pos, Expected & expected, std::vector<ASTCreateQuotaQuery::Limits> & all_limits, bool alter) |
177 | { |
178 | return IParserBase::wrapParseImpl(pos, [&] |
179 | { |
180 | do |
181 | { |
182 | ASTCreateQuotaQuery::Limits limits; |
183 | if (!parseLimits(pos, expected, limits, alter)) |
184 | return false; |
185 | all_limits.push_back(limits); |
186 | } |
187 | while (ParserToken{TokenType::Comma}.ignore(pos, expected)); |
188 | return true; |
189 | }); |
190 | } |
191 | |
192 | bool parseRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTRoleList> & roles) |
193 | { |
194 | return IParserBase::wrapParseImpl(pos, [&] |
195 | { |
196 | ASTPtr node; |
197 | if (roles || !ParserKeyword{"TO" }.ignore(pos, expected) || !ParserRoleList{}.parse(pos, node, expected)) |
198 | return false; |
199 | |
200 | roles = std::static_pointer_cast<ASTRoleList>(node); |
201 | return true; |
202 | }); |
203 | } |
204 | } |
205 | |
206 | |
207 | bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) |
208 | { |
209 | bool alter; |
210 | if (ParserKeyword{"CREATE QUOTA" }.ignore(pos, expected)) |
211 | alter = false; |
212 | else if (ParserKeyword{"ALTER QUOTA" }.ignore(pos, expected)) |
213 | alter = true; |
214 | else |
215 | return false; |
216 | |
217 | bool if_exists = false; |
218 | bool if_not_exists = false; |
219 | bool or_replace = false; |
220 | if (alter) |
221 | { |
222 | if (ParserKeyword{"IF EXISTS" }.ignore(pos, expected)) |
223 | if_exists = true; |
224 | } |
225 | else |
226 | { |
227 | if (ParserKeyword{"IF NOT EXISTS" }.ignore(pos, expected)) |
228 | if_not_exists = true; |
229 | else if (ParserKeyword{"OR REPLACE" }.ignore(pos, expected)) |
230 | or_replace = true; |
231 | } |
232 | |
233 | String name; |
234 | if (!parseIdentifierOrStringLiteral(pos, expected, name)) |
235 | return false; |
236 | |
237 | String new_name; |
238 | std::optional<KeyType> key_type; |
239 | std::vector<ASTCreateQuotaQuery::Limits> all_limits; |
240 | std::shared_ptr<ASTRoleList> roles; |
241 | |
242 | while (parseRenameTo(pos, expected, new_name, alter) || parseKeyType(pos, expected, key_type) |
243 | || parseAllLimits(pos, expected, all_limits, alter) || parseRoles(pos, expected, roles)) |
244 | ; |
245 | |
246 | auto query = std::make_shared<ASTCreateQuotaQuery>(); |
247 | node = query; |
248 | |
249 | query->alter = alter; |
250 | query->if_exists = if_exists; |
251 | query->if_not_exists = if_not_exists; |
252 | query->or_replace = or_replace; |
253 | query->name = std::move(name); |
254 | query->new_name = std::move(new_name); |
255 | query->key_type = key_type; |
256 | query->all_limits = std::move(all_limits); |
257 | query->roles = std::move(roles); |
258 | |
259 | return true; |
260 | } |
261 | } |
262 | |