/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/ql_processor.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //-------------------------------------------------------------------------------------------------- |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
5 | | // in compliance with the License. You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
10 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
11 | | // or implied. See the License for the specific language governing permissions and limitations |
12 | | // under the License. |
13 | | // |
14 | | //-------------------------------------------------------------------------------------------------- |
15 | | |
16 | | #include "yb/yql/cql/ql/ql_processor.h" |
17 | | |
18 | | #include <memory> |
19 | | |
20 | | #include "yb/client/table.h" |
21 | | #include "yb/client/yb_table_name.h" |
22 | | |
23 | | #include "yb/common/index.h" |
24 | | |
25 | | #include "yb/gutil/bind.h" |
26 | | |
27 | | #include "yb/util/metrics.h" |
28 | | #include "yb/util/scope_exit.h" |
29 | | #include "yb/util/status_format.h" |
30 | | #include "yb/util/thread_restrictions.h" |
31 | | |
32 | | #include "yb/yql/cql/ql/parser/parser.h" |
33 | | |
34 | | DECLARE_bool(use_cassandra_authentication); |
35 | | DECLARE_bool(ycql_require_drop_privs_for_truncate); |
36 | | |
37 | | METRIC_DEFINE_histogram_with_percentiles( |
38 | | server, handler_latency_yb_cqlserver_SQLProcessor_ParseRequest, |
39 | | "Time spent parsing the SQL query", yb::MetricUnit::kMicroseconds, |
40 | | "Time spent parsing the SQL query", 60000000LU, 2); |
41 | | METRIC_DEFINE_histogram_with_percentiles( |
42 | | server, handler_latency_yb_cqlserver_SQLProcessor_AnalyzeRequest, |
43 | | "Time spent to analyze the parsed SQL query", yb::MetricUnit::kMicroseconds, |
44 | | "Time spent to analyze the parsed SQL query", 60000000LU, 2); |
45 | | METRIC_DEFINE_histogram_with_percentiles( |
46 | | server, handler_latency_yb_cqlserver_SQLProcessor_ExecuteRequest, |
47 | | "Time spent executing the parsed SQL query", yb::MetricUnit::kMicroseconds, |
48 | | "Time spent executing the parsed SQL query", 60000000LU, 2); |
49 | | METRIC_DEFINE_histogram_with_percentiles( |
50 | | server, handler_latency_yb_cqlserver_SQLProcessor_NumRoundsToAnalyze, |
51 | | "Number of rounds to successfully parse a SQL query", yb::MetricUnit::kOperations, |
52 | | "Number of rounds to successfully parse a SQL query", 60000000LU, 2); |
53 | | METRIC_DEFINE_histogram_with_percentiles( |
54 | | server, handler_latency_yb_cqlserver_SQLProcessor_NumRetriesToExecute, |
55 | | "Number of retries to successfully execute a SQL query", yb::MetricUnit::kOperations, |
56 | | "Number of retries to successfully execute a SQL query", 60000000LU, 2); |
57 | | METRIC_DEFINE_histogram_with_percentiles( |
58 | | server, handler_latency_yb_cqlserver_SQLProcessor_NumFlushesToExecute, |
59 | | "Number of flushes to successfully execute a SQL query", yb::MetricUnit::kOperations, |
60 | | "Number of flushes to successfully execute a SQL query", 60000000LU, 2); |
61 | | METRIC_DEFINE_histogram_with_percentiles( |
62 | | server, handler_latency_yb_cqlserver_SQLProcessor_SelectStmt, |
63 | | "Time spent processing a SELECT statement", yb::MetricUnit::kMicroseconds, |
64 | | "Time spent processing a SELECT statement", 60000000LU, 2); |
65 | | METRIC_DEFINE_histogram_with_percentiles( |
66 | | server, handler_latency_yb_cqlserver_SQLProcessor_InsertStmt, |
67 | | "Time spent processing an INSERT statement", yb::MetricUnit::kMicroseconds, |
68 | | "Time spent processing an INSERT statement", 60000000LU, 2); |
69 | | METRIC_DEFINE_histogram_with_percentiles( |
70 | | server, handler_latency_yb_cqlserver_SQLProcessor_UpdateStmt, |
71 | | "Time spent processing an UPDATE statement", yb::MetricUnit::kMicroseconds, |
72 | | "Time spent processing an UPDATE statement", 60000000LU, 2); |
73 | | METRIC_DEFINE_histogram_with_percentiles( |
74 | | server, handler_latency_yb_cqlserver_SQLProcessor_DeleteStmt, |
75 | | "Time spent processing a DELETE statement", yb::MetricUnit::kMicroseconds, |
76 | | "Time spent processing a DELETE statement", 60000000LU, 2); |
77 | | METRIC_DEFINE_histogram_with_percentiles( |
78 | | server, handler_latency_yb_cqlserver_SQLProcessor_UseStmt, |
79 | | "Time spent processing a USE statement", yb::MetricUnit::kMicroseconds, |
80 | | "Time spent processing a USE statement", 60000000LU, 2); |
81 | | METRIC_DEFINE_histogram_with_percentiles( |
82 | | server, handler_latency_yb_cqlserver_SQLProcessor_OtherStmts, |
83 | | "Time spent processing any statement other than SELECT/INSERT/UPDATE/DELETE", |
84 | | yb::MetricUnit::kMicroseconds, |
85 | | "Time spent processing any statement other than SELECT/INSERT/UPDATE/DELETE", 60000000LU, 2); |
86 | | METRIC_DEFINE_histogram_with_percentiles( |
87 | | server, handler_latency_yb_cqlserver_SQLProcessor_Transaction, |
88 | | "Time spent processing a transaction", yb::MetricUnit::kMicroseconds, |
89 | | "Time spent processing a transaction", 60000000LU, 2); |
90 | | METRIC_DEFINE_histogram_with_percentiles( |
91 | | server, handler_latency_yb_cqlserver_SQLProcessor_ResponseSize, |
92 | | "Size of the returned response blob (in bytes)", yb::MetricUnit::kBytes, |
93 | | "Size of the returned response blob (in bytes)", 60000000LU, 2); |
94 | | |
95 | | namespace yb { |
96 | | namespace ql { |
97 | | |
98 | | using std::shared_ptr; |
99 | | using std::string; |
100 | | using client::YBClient; |
101 | | using client::YBMetaDataCache; |
102 | | using client::YBTableName; |
103 | | using ql::audit::IsPrepare; |
104 | | using ql::audit::ErrorIsFormatted; |
105 | | |
106 | 6.11k | QLMetrics::QLMetrics(const scoped_refptr<yb::MetricEntity> &metric_entity) { |
107 | 6.11k | time_to_parse_ql_query_ = |
108 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_ParseRequest.Instantiate(metric_entity); |
109 | 6.11k | time_to_analyze_ql_query_ = |
110 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_AnalyzeRequest.Instantiate(metric_entity); |
111 | 6.11k | time_to_execute_ql_query_ = |
112 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_ExecuteRequest.Instantiate(metric_entity); |
113 | 6.11k | num_rounds_to_analyze_ql_ = |
114 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_NumRoundsToAnalyze.Instantiate( |
115 | 6.11k | metric_entity); |
116 | 6.11k | num_retries_to_execute_ql_ = |
117 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_NumRetriesToExecute.Instantiate( |
118 | 6.11k | metric_entity); |
119 | 6.11k | num_flushes_to_execute_ql_ = |
120 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_NumFlushesToExecute.Instantiate( |
121 | 6.11k | metric_entity); |
122 | | |
123 | 6.11k | ql_select_ = |
124 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_SelectStmt.Instantiate(metric_entity); |
125 | 6.11k | ql_insert_ = |
126 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_InsertStmt.Instantiate(metric_entity); |
127 | 6.11k | ql_update_ = |
128 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_UpdateStmt.Instantiate(metric_entity); |
129 | 6.11k | ql_delete_ = |
130 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_DeleteStmt.Instantiate(metric_entity); |
131 | 6.11k | ql_use_ = |
132 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_UseStmt.Instantiate(metric_entity); |
133 | 6.11k | ql_others_ = |
134 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_OtherStmts.Instantiate(metric_entity); |
135 | 6.11k | ql_transaction_ = |
136 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_Transaction.Instantiate(metric_entity); |
137 | | |
138 | 6.11k | ql_response_size_bytes_ = |
139 | 6.11k | METRIC_handler_latency_yb_cqlserver_SQLProcessor_ResponseSize.Instantiate(metric_entity); |
140 | 6.11k | } |
141 | | |
142 | 0 | QLMetrics::~QLMetrics() = default; |
143 | | |
144 | | namespace { |
145 | | |
146 | | ThreadSafeObjectPool<Parser> default_parser_pool; |
147 | | |
148 | | } |
149 | | |
150 | | QLProcessor::QLProcessor(client::YBClient* client, |
151 | | shared_ptr<YBMetaDataCache> cache, QLMetrics* ql_metrics, |
152 | | ThreadSafeObjectPool<Parser>* parser_pool, |
153 | | const server::ClockPtr& clock, |
154 | | TransactionPoolProvider transaction_pool_provider) |
155 | | : ql_env_(client, cache, clock, std::move(transaction_pool_provider)), |
156 | | audit_logger_(ql_env_), |
157 | | analyzer_(&ql_env_), |
158 | | executor_(&ql_env_, &audit_logger_, this, ql_metrics), |
159 | | ql_metrics_(ql_metrics), |
160 | 18.1k | parser_pool_(parser_pool ? parser_pool : &default_parser_pool) { |
161 | 18.1k | } |
162 | | |
163 | 1 | QLProcessor::~QLProcessor() { |
164 | 1 | } |
165 | | |
166 | | Status QLProcessor::Parse(const string& stmt, ParseTree::UniPtr* parse_tree, |
167 | | const bool reparsed, const MemTrackerPtr& mem_tracker, |
168 | 342k | const bool internal) { |
169 | | // Parse the statement and get the generated parse tree. |
170 | 342k | const MonoTime begin_time = MonoTime::Now(); |
171 | 342k | auto* parser = parser_pool_->Take(); |
172 | 342k | auto scope_exit = ScopeExit([this, parser] { |
173 | 338k | this->parser_pool_->Release(parser); |
174 | 338k | }); |
175 | 342k | const Status s = parser->Parse(stmt, reparsed, mem_tracker, internal); |
176 | 342k | const MonoTime end_time = MonoTime::Now(); |
177 | 342k | if (ql_metrics_ != nullptr) { |
178 | 339k | const MonoDelta elapsed_time = end_time.GetDeltaSince(begin_time); |
179 | 339k | ql_metrics_->time_to_parse_ql_query_->Increment(elapsed_time.ToMicroseconds()); |
180 | 339k | } |
181 | 342k | if (!s.ok()) { |
182 | 96 | RETURN_NOT_OK(audit_logger_.LogStatementError(stmt, s, ErrorIsFormatted::kTrue)); |
183 | 96 | return s; |
184 | 96 | } |
185 | 342k | *parse_tree = parser->Done(); |
186 | 342k | DCHECK(*parse_tree) << "Parse tree is null"3.77k ; |
187 | 342k | return Status::OK(); |
188 | 342k | } |
189 | | |
190 | 338k | Status QLProcessor::Analyze(ParseTree::UniPtr* parse_tree) { |
191 | | // Semantic analysis - traverse, error-check, and decorate the parse tree nodes with datatypes. |
192 | 338k | const MonoTime begin_time = MonoTime::Now(); |
193 | 338k | const Status s = analyzer_.Analyze(std::move(*parse_tree)); |
194 | 338k | const MonoTime end_time = MonoTime::Now(); |
195 | 341k | if (ql_metrics_ != nullptr338k ) { |
196 | 341k | const MonoDelta elapsed_time = end_time.GetDeltaSince(begin_time); |
197 | 341k | ql_metrics_->time_to_analyze_ql_query_->Increment(elapsed_time.ToMicroseconds()); |
198 | 341k | ql_metrics_->num_rounds_to_analyze_ql_->Increment(1); |
199 | 341k | } |
200 | 338k | *parse_tree = analyzer_.Done(); |
201 | 18.4E | DCHECK(*parse_tree) << "Parse tree is null"; |
202 | 338k | return s; |
203 | 338k | } |
204 | | |
205 | | Status QLProcessor::Prepare(const string& stmt, ParseTree::UniPtr* parse_tree, |
206 | | const bool reparsed, const MemTrackerPtr& mem_tracker, |
207 | 341k | const bool internal) { |
208 | 341k | RETURN_NOT_OK(Parse(stmt, parse_tree, reparsed, mem_tracker, internal)); |
209 | 341k | Status s = Analyze(parse_tree); |
210 | 341k | if (s.IsQLError() && GetErrorCode(s) == ErrorCode::STALE_METADATA1.08k && !reparsed414 ) { |
211 | 414 | *parse_tree = nullptr; |
212 | 414 | RETURN_NOT_OK(Parse(stmt, parse_tree, true /* reparsed */, mem_tracker)); |
213 | 414 | s = Analyze(parse_tree); |
214 | 414 | } |
215 | 341k | if (s.IsQLError()) { |
216 | 1.03k | RETURN_NOT_OK(audit_logger_.LogStatementError((*parse_tree)->root().get(), stmt, s, |
217 | 1.03k | ErrorIsFormatted::kTrue)); |
218 | 1.03k | } |
219 | 341k | return s; |
220 | 341k | } |
221 | | |
222 | 124k | bool QLProcessor::CheckPermissions(const ParseTree& parse_tree, StatementExecutedCallback cb) { |
223 | 124k | const TreeNode* tnode = parse_tree.root().get(); |
224 | 124k | if (tnode != nullptr) { |
225 | 123k | Status s = CheckNodePermissions(tnode); |
226 | 123k | if (!s.ok()) { |
227 | 60 | cb.Run(s, nullptr); |
228 | 60 | return false; |
229 | 60 | } |
230 | 123k | } |
231 | 123k | return true; |
232 | 124k | } |
233 | | |
234 | 123k | Status QLProcessor::CheckNodePermissions(const TreeNode* tnode) { |
235 | 123k | Status s; // OK by default initialization. |
236 | 123k | switch (DCHECK_NOTNULL(tnode)->opcode()) { |
237 | 906 | case TreeNodeOpcode::kPTCreateKeyspace: |
238 | 906 | s = ql_env_.HasResourcePermission( |
239 | 906 | "data", ObjectType::SCHEMA, PermissionType::CREATE_PERMISSION); |
240 | 906 | break; |
241 | 237 | case TreeNodeOpcode::kPTCreateTable: { |
242 | 237 | const char* keyspace = |
243 | 237 | static_cast<const PTCreateTable*>(tnode)->table_name()->first_name().c_str(); |
244 | 237 | s = ql_env_.HasResourcePermission(get_canonical_keyspace(keyspace), ObjectType::SCHEMA, |
245 | 237 | PermissionType::CREATE_PERMISSION, keyspace); |
246 | 237 | break; |
247 | 0 | } |
248 | 24 | case TreeNodeOpcode::kPTCreateType: |
249 | | // Check has AllKeyspaces permission. |
250 | 24 | s = ql_env_.HasResourcePermission( |
251 | 24 | "data", ObjectType::SCHEMA, PermissionType::CREATE_PERMISSION); |
252 | 24 | if (!s.ok()) { |
253 | 16 | const string keyspace = |
254 | 16 | static_cast<const PTCreateType*>(tnode)->yb_type_name().namespace_name(); |
255 | | // Check has Keyspace permission. |
256 | 16 | s = ql_env_.HasResourcePermission(get_canonical_keyspace(keyspace), |
257 | 16 | ObjectType::SCHEMA, PermissionType::CREATE_PERMISSION, keyspace); |
258 | 16 | } |
259 | 24 | break; |
260 | 7 | case TreeNodeOpcode::kPTCreateIndex: { |
261 | 7 | const YBTableName indexed_table_name = |
262 | 7 | static_cast<const PTCreateIndex*>(tnode)->indexed_table_name(); |
263 | 7 | s = ql_env_.HasTablePermission(indexed_table_name, PermissionType::ALTER_PERMISSION); |
264 | 7 | break; |
265 | 0 | } |
266 | 8 | case TreeNodeOpcode::kPTAlterTable: { |
267 | 8 | const YBTableName table_name = static_cast<const PTAlterTable*>(tnode)->yb_table_name(); |
268 | 8 | s = ql_env_.HasTablePermission(table_name, PermissionType::ALTER_PERMISSION); |
269 | 8 | break; |
270 | 0 | } |
271 | 17 | case TreeNodeOpcode::kPTTruncateStmt: { |
272 | 17 | const YBTableName table_name = static_cast<const PTTruncateStmt*>(tnode)->yb_table_name(); |
273 | 17 | if (FLAGS_ycql_require_drop_privs_for_truncate) { |
274 | 7 | s = ql_env_.HasTablePermission(table_name, PermissionType::DROP_PERMISSION); |
275 | 10 | } else { |
276 | 10 | s = ql_env_.HasTablePermission(table_name, PermissionType::MODIFY_PERMISSION); |
277 | 10 | } |
278 | 17 | break; |
279 | 0 | } |
280 | 2 | case TreeNodeOpcode::kPTExplainStmt: { |
281 | 2 | const PTExplainStmt* explain_stmt = static_cast<const PTExplainStmt*>(tnode); |
282 | 2 | s = CheckNodePermissions(DCHECK_NOTNULL(explain_stmt->stmt().get())); |
283 | 2 | break; |
284 | 0 | } |
285 | 19 | case TreeNodeOpcode::kPTUpdateStmt: FALLTHROUGH_INTENDED; |
286 | 27 | case TreeNodeOpcode::kPTDeleteStmt: FALLTHROUGH_INTENDED; |
287 | 155 | case TreeNodeOpcode::kPTInsertStmt: { |
288 | 155 | DCHECK(tnode->IsDml()); |
289 | 155 | const YBTableName table_name = static_cast<const PTDmlStmt*>(tnode)->table_name(); |
290 | 155 | s = ql_env_.HasTablePermission(table_name, PermissionType::MODIFY_PERMISSION); |
291 | 155 | break; |
292 | 27 | } |
293 | 117k | case TreeNodeOpcode::kPTSelectStmt: { |
294 | 117k | const auto select_stmt = static_cast<const PTSelectStmt*>(tnode); |
295 | 117k | if (select_stmt->IsReadableByAllSystemTable()) { |
296 | 115k | break; |
297 | 115k | } |
298 | 1.61k | const YBTableName table_name = select_stmt->table_name(); |
299 | 1.61k | s = ql_env_.HasTablePermission(table_name, PermissionType::SELECT_PERMISSION); |
300 | 1.61k | break; |
301 | 117k | } |
302 | 757 | case TreeNodeOpcode::kPTCreateRole: |
303 | 757 | s = ql_env_.HasResourcePermission("roles", ObjectType::ROLE, |
304 | 757 | PermissionType::CREATE_PERMISSION); |
305 | 757 | break; |
306 | 58 | case TreeNodeOpcode::kPTAlterRole: { |
307 | 58 | const char* role = static_cast<const PTAlterRole*>(tnode)->role_name(); |
308 | 58 | s = ql_env_.HasRolePermission(role, PermissionType::ALTER_PERMISSION); |
309 | 58 | break; |
310 | 117k | } |
311 | 60 | case TreeNodeOpcode::kPTGrantRevokeRole: { |
312 | 60 | const auto grant_revoke_role_stmt = static_cast<const PTGrantRevokeRole*>(tnode); |
313 | 60 | const string granted_role = grant_revoke_role_stmt->granted_role_name(); |
314 | 60 | const string recipient_role = grant_revoke_role_stmt->recipient_role_name(); |
315 | 60 | s = ql_env_.HasRolePermission(granted_role, PermissionType::AUTHORIZE_PERMISSION); |
316 | 60 | if (s.ok()) { |
317 | 52 | s = ql_env_.HasRolePermission(recipient_role, PermissionType::AUTHORIZE_PERMISSION); |
318 | 52 | } |
319 | 60 | break; |
320 | 117k | } |
321 | 731 | case TreeNodeOpcode::kPTGrantRevokePermission: { |
322 | 731 | const auto grant_revoke_permission = static_cast<const PTGrantRevokePermission*>(tnode); |
323 | 731 | const string canonical_resource = grant_revoke_permission->canonical_resource(); |
324 | 731 | const char* keyspace = grant_revoke_permission->namespace_name(); |
325 | | // It's only a table name if the resource type is TABLE. |
326 | 731 | const char* table = grant_revoke_permission->resource_name(); |
327 | 731 | switch (grant_revoke_permission->resource_type()) { |
328 | 238 | case ResourceType::KEYSPACE: { |
329 | 238 | DCHECK_EQ(canonical_resource, get_canonical_keyspace(keyspace)); |
330 | 238 | s = ql_env_.HasResourcePermission(canonical_resource, ObjectType::SCHEMA, |
331 | 238 | PermissionType::AUTHORIZE_PERMISSION, |
332 | 238 | keyspace); |
333 | 238 | break; |
334 | 0 | } |
335 | 201 | case ResourceType::TABLE: { |
336 | 201 | DCHECK_EQ(canonical_resource, get_canonical_table(keyspace, table)); |
337 | 201 | s = ql_env_.HasTablePermission(keyspace, table, PermissionType::AUTHORIZE_PERMISSION); |
338 | 201 | break; |
339 | 0 | } |
340 | 87 | case ResourceType::ROLE: { |
341 | 87 | DCHECK_EQ(canonical_resource, |
342 | 87 | get_canonical_role(grant_revoke_permission->resource_name())); |
343 | 87 | s = ql_env_.HasResourcePermission(canonical_resource, ObjectType::ROLE, |
344 | 87 | PermissionType::AUTHORIZE_PERMISSION); |
345 | 87 | break; |
346 | 0 | } |
347 | 138 | case ResourceType::ALL_KEYSPACES: { |
348 | 138 | DCHECK_EQ(canonical_resource, "data"); |
349 | 138 | s = ql_env_.HasResourcePermission(canonical_resource, ObjectType::SCHEMA, |
350 | 138 | PermissionType::AUTHORIZE_PERMISSION); |
351 | 138 | break; |
352 | 0 | } |
353 | 67 | case ResourceType::ALL_ROLES: |
354 | 67 | DCHECK_EQ(canonical_resource, "roles"); |
355 | 67 | s = ql_env_.HasResourcePermission(canonical_resource, ObjectType::ROLE, |
356 | 67 | PermissionType::AUTHORIZE_PERMISSION); |
357 | 67 | break; |
358 | 731 | } |
359 | 731 | break; |
360 | 731 | } |
361 | 1.87k | case TreeNodeOpcode::kPTDropStmt: { |
362 | 1.87k | const auto drop_stmt = static_cast<const PTDropStmt*>(tnode); |
363 | 1.87k | const ObjectType object_type = drop_stmt->drop_type(); |
364 | 1.87k | switch(object_type) { |
365 | 732 | case ObjectType::ROLE: |
366 | 732 | s = ql_env_.HasRolePermission(drop_stmt->name()->QLName(), |
367 | 732 | PermissionType::DROP_PERMISSION); |
368 | 732 | break; |
369 | 874 | case ObjectType::SCHEMA: |
370 | 874 | s = ql_env_.HasResourcePermission( |
371 | 874 | get_canonical_keyspace(drop_stmt->yb_table_name().namespace_name()), |
372 | 874 | ObjectType::SCHEMA, PermissionType::DROP_PERMISSION); |
373 | 874 | break; |
374 | 237 | case ObjectType::TABLE: |
375 | 237 | s = ql_env_.HasTablePermission(drop_stmt->yb_table_name(), |
376 | 237 | PermissionType::DROP_PERMISSION); |
377 | 237 | break; |
378 | 24 | case ObjectType::TYPE: |
379 | | // Check has AllKeyspaces permission. |
380 | 24 | s = ql_env_.HasResourcePermission( |
381 | 24 | "data", ObjectType::SCHEMA, PermissionType::DROP_PERMISSION); |
382 | 24 | if (!s.ok()) { |
383 | 20 | const string keyspace = drop_stmt->yb_table_name().namespace_name(); |
384 | | // Check has Keyspace permission. |
385 | 20 | s = ql_env_.HasResourcePermission(get_canonical_keyspace(keyspace), |
386 | 20 | ObjectType::SCHEMA, PermissionType::DROP_PERMISSION, keyspace); |
387 | 20 | } |
388 | 24 | break; |
389 | 4 | case ObjectType::INDEX: { |
390 | 4 | bool cache_used = false; |
391 | 4 | const YBTableName table_name(YQL_DATABASE_CQL, |
392 | 4 | drop_stmt->yb_table_name().namespace_name(), |
393 | 4 | drop_stmt->yb_table_name().table_name()); |
394 | 4 | std::shared_ptr<client::YBTable> table = ql_env_.GetTableDesc(table_name, &cache_used); |
395 | | |
396 | | // If the table is not found, or if it's not an index, let the operation go through |
397 | | // so that we can return a "not found" error.s |
398 | 4 | if (table && table->IsIndex()) { |
399 | 4 | std::shared_ptr<client::YBTable> indexed_table = |
400 | 4 | ql_env_.GetTableDesc(table->index_info().indexed_table_id(), &cache_used); |
401 | | |
402 | 4 | if (!indexed_table) { |
403 | 0 | s = STATUS_SUBSTITUTE(InternalError, |
404 | 0 | "Unable to find index $0", |
405 | 0 | drop_stmt->name()->QLName()); |
406 | 0 | break; |
407 | 0 | } |
408 | | |
409 | 4 | s = ql_env_.HasTablePermission(indexed_table->name(), |
410 | 4 | PermissionType::ALTER_PERMISSION); |
411 | 4 | } |
412 | 4 | break; |
413 | 4 | } |
414 | 4 | default: |
415 | 0 | break; |
416 | 1.87k | } |
417 | 1.87k | break; |
418 | 1.87k | } |
419 | 2.05k | default: |
420 | 2.05k | break; |
421 | 123k | } |
422 | 123k | return s; |
423 | 123k | } |
424 | | |
425 | | void QLProcessor::ExecuteAsync(const ParseTree& parse_tree, const StatementParameters& params, |
426 | 9.09M | StatementExecutedCallback cb) { |
427 | 9.09M | if (FLAGS_use_cassandra_authentication && !parse_tree.internal()129k ) { |
428 | 123k | if (!CheckPermissions(parse_tree, cb)) { |
429 | 60 | return; |
430 | 60 | } |
431 | 123k | } |
432 | 9.09M | executor_.ExecuteAsync(parse_tree, params, std::move(cb)); |
433 | 9.09M | } |
434 | | |
435 | 1.62k | void QLProcessor::ExecuteAsync(const StatementBatch& batch, StatementExecutedCallback cb) { |
436 | 1.62k | executor_.ExecuteAsync(batch, std::move(cb)); |
437 | 1.62k | } |
438 | | |
439 | | void QLProcessor::RunAsync(const string& stmt, const StatementParameters& params, |
440 | 337k | StatementExecutedCallback cb, const bool reparsed) { |
441 | 337k | ParseTree::UniPtr parse_tree; |
442 | 337k | const Status s = Prepare(stmt, &parse_tree, reparsed); |
443 | 337k | if (PREDICT_FALSE(!s.ok())) { |
444 | 962 | return cb.Run(s, nullptr /* result */); |
445 | 962 | } |
446 | 336k | const ParseTree* ptree = parse_tree.release(); |
447 | | // Do not make a copy of stmt and params when binding to the RunAsyncDone callback because when |
448 | | // error occurs due to stale matadata, the statement needs to be reexecuted. We should pass the |
449 | | // original references which are guaranteed to still be alive when the statement is reexecuted. |
450 | 336k | ExecuteAsync(*ptree, params, Bind(&QLProcessor::RunAsyncDone, Unretained(this), ConstRef(stmt), |
451 | 336k | ConstRef(params), Owned(ptree), cb)); |
452 | 336k | } |
453 | | |
454 | | void QLProcessor::RunAsyncDone(const string& stmt, const StatementParameters& params, |
455 | | const ParseTree* parse_tree, StatementExecutedCallback cb, |
456 | 335k | const Status& s, const ExecutedResult::SharedPtr& result) { |
457 | | // If execution fails due to stale metadata and the statement has not been reparsed, rerun this |
458 | | // statement with stale metadata flushed. The rerun needs to be rescheduled in because this |
459 | | // callback may not be executed in the RPC worker thread. Also, rescheduling gives other calls a |
460 | | // chance to execute first before we do. |
461 | 335k | if (s.IsQLError() && GetErrorCode(s) == ErrorCode::STALE_METADATA3.21k && !parse_tree->reparsed()570 ) { |
462 | 570 | return Reschedule(&run_async_task_.Bind(this, stmt, params, std::move(cb))); |
463 | 570 | } |
464 | 335k | cb.Run(s, result); |
465 | 335k | } |
466 | | |
467 | 1 | void QLProcessor::Reschedule(rpc::ThreadPoolTask* task) { |
468 | 1 | is_rescheduled_.store(IsRescheduled::kTrue, std::memory_order_release); |
469 | | // Some unit tests are not executed in CQL proxy. In those cases, just execute the callback |
470 | | // directly while disabling thread restrictions. |
471 | 1 | const bool allowed = ThreadRestrictions::SetWaitAllowed(true); |
472 | 1 | task->Run(); |
473 | | // In such tests QLProcessor is deleted right after Run is executed, since QLProcessor tasks |
474 | | // do nothing in Done we could just don't execute it. |
475 | | // task->Done(Status::OK()); |
476 | 1 | ThreadRestrictions::SetWaitAllowed(allowed); |
477 | 1 | } |
478 | | |
479 | 1 | CoarseTimePoint QLProcessor::GetDeadline() const { |
480 | | // Used only in tests. |
481 | 1 | return CoarseMonoClock::now() + MonoDelta::FromSeconds(60); |
482 | 1 | } |
483 | | |
484 | | } // namespace ql |
485 | | } // namespace yb |