YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/exec/exec_context.h
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
// This class represents the context to execute a single statment. It contains the statement code
16
// (parse tree) and the environment (parameters and session context) with which the code is to be
17
// executed.
18
//--------------------------------------------------------------------------------------------------
19
20
#ifndef YB_YQL_CQL_QL_EXEC_EXEC_CONTEXT_H_
21
#define YB_YQL_CQL_QL_EXEC_EXEC_CONTEXT_H_
22
23
#include <string>
24
25
#include <rapidjson/document.h>
26
27
#include "yb/client/session.h"
28
29
#include "yb/common/ql_protocol.pb.h"
30
31
#include "yb/util/status_fwd.h"
32
33
#include "yb/yql/cql/ql/exec/exec_fwd.h"
34
#include "yb/yql/cql/ql/ptree/process_context.h"
35
#include "yb/yql/cql/ql/util/statement_result.h"
36
37
namespace yb {
38
namespace ql {
39
40
//--------------------------------------------------------------------------------------------------
41
// In addition to actual data, a CQL result contains a paging state for the CURSOR position.
42
//
43
// QueryPagingState represents the processing status in both CQL and DocDB. This class is used
44
// for those purposes.
45
//
46
// 1. Load paging state from users and docdb.
47
//    - When users send request, they sent StatementParams that contain user data and a paging
48
//      state that indicates the status the statement execution.
49
//    - When CQL gets the request, it loads user-provided paging state to ql::QueryPagingState.
50
//
51
// 2. Compose paging_state when sending replies to users.
52
//    - When responding to user, in addition to row-data, CQL construct paging-state of its
53
//      processing status, and CQL uses info in ql::SelectPagingState to construct the response.
54
//    - In subsequent requests, users will send this info back to CQL together with user-data.
55
//
56
// 3. Load paging state from docdb.
57
//    - In addition to actual row data, when DocDB replies to CQL, it sends back its paging state
58
//      to indicate the status of DocDB's processing.
59
//    - CQL will load DocDB's paging state into ql::QueryPagingState.
60
//    - In subsequent READ requests, CQL sends back paging state to DocDB.
61
//
62
// 4. Compose paging_state when sending request to DocDB.
63
//    - When sending requests to DocDB, CQL sends a paging state in addition to user data.
64
//    - CQL uses info in QueryPagingState to construct DocDB's paging state.
65
class QueryPagingState {
66
 public:
67
  typedef std::unique_ptr<QueryPagingState> UniPtr;
68
69
  // Constructing paging_state from given user_params.
70
  QueryPagingState(const StatementParameters& user_params, bool is_top_level_select);
71
72
  // Clear paging state.
73
  // NOTE:
74
  // - Clear only query_pb_.
75
  // - The counter_pb_ are used only in this class and should not be cleared.
76
  // - DocDB as well as users do not know of this counter.
77
  void ClearPagingState();
78
79
  // Load the paging state in user request.
80
  void LoadPagingStateFromUser(const StatementParameters& params,
81
                                              bool is_top_level_read_node);
82
83
  // Compose paging state to send to users.
84
  CHECKED_STATUS ComposePagingStateForUser();
85
  CHECKED_STATUS ComposePagingStateForUser(const QLPagingStatePB& child_state);
86
87
  // Load the paging state in DocDB responses.
88
  CHECKED_STATUS LoadPagingStateFromDocdb(const RowsResult::SharedPtr& rows_result,
89
                                          int64_t number_of_new_rows,
90
                                          bool has_nested_query);
91
92
  // Access functions to query_pb_.
93
0
  const std::string& table_id() const {
94
0
    return query_pb_.table_id();
95
0
  }
96
97
282
  void set_table_id(const std::string& val) {
98
282
    query_pb_.set_table_id(val);
99
282
  }
100
101
67.4k
  const std::string& next_partition_key() const {
102
67.4k
    return query_pb_.next_partition_key();
103
67.4k
  }
104
105
0
  void set_next_partition_key(const std::string& val) {
106
0
    query_pb_.set_next_partition_key(val);
107
0
  }
108
109
34.2k
  const std::string& next_row_key() const {
110
34.2k
    return query_pb_.next_row_key();
111
34.2k
  }
112
113
0
  void set_next_row_key(const std::string& val) {
114
0
    query_pb_.set_next_row_key(val);
115
0
  }
116
117
279
  int64_t total_num_rows_read() const {
118
279
    return query_pb_.total_num_rows_read();
119
279
  }
120
121
282
  void set_total_num_rows_read(int64_t val) {
122
282
    query_pb_.set_total_num_rows_read(val);
123
282
  }
124
125
3.93M
  int64_t total_rows_skipped() const {
126
3.93M
    return query_pb_.total_rows_skipped();
127
3.93M
  }
128
129
282
  void set_total_rows_skipped(int64_t val) {
130
282
    query_pb_.set_total_rows_skipped(val);
131
282
  }
132
133
16
  int64_t next_partition_index() const {
134
16
    return query_pb_.next_partition_index();
135
16
  }
136
137
282
  void set_next_partition_index(int64_t val) {
138
282
    query_pb_.set_next_partition_index(val);
139
282
  }
140
141
  // It appears the folliwng fields are not used.
142
282
  void set_original_request_id(int64_t val) {
143
282
    query_pb_.set_original_request_id(val);
144
282
  }
145
146
  // Access function to counter_pb_ - Predicate for (LIMIT, OFFSET).
147
3.62M
  bool has_select_limit() const {
148
3.62M
    return counter_pb_.has_select_limit();
149
3.62M
  }
150
151
3.94M
  bool has_select_offset() const {
152
3.94M
    return counter_pb_.has_select_offset();
153
3.94M
  }
154
155
  // row-read counters.
156
3.93M
  void set_read_count(size_t val) {
157
3.93M
    counter_pb_.set_read_count(val);
158
3.93M
  }
159
160
22.0M
  int64_t read_count() const {
161
22.0M
    return counter_pb_.read_count();
162
22.0M
  }
163
164
  // row-skip counter.
165
1.86k
  void set_skip_count(size_t val) {
166
1.86k
    counter_pb_.set_skip_count(val);
167
1.86k
  }
168
169
35.9k
  int64_t skip_count() const {
170
35.9k
    return counter_pb_.skip_count();
171
35.9k
  }
172
173
  // row limit counter processing.
174
3.62M
  void set_select_limit(size_t val) {
175
3.62M
    counter_pb_.set_select_limit(val);
176
3.62M
  }
177
178
18.0M
  int64_t select_limit() const {
179
18.0M
    return counter_pb_.select_limit();
180
18.0M
  }
181
182
11.4M
  bool reached_select_limit() const {
183
11.4M
    return counter_pb_.has_select_limit() && read_count() >= select_limit();
184
11.4M
  }
185
186
  // row offset counter processing.
187
249
  void set_select_offset(size_t val) {
188
249
    counter_pb_.set_select_offset(val);
189
249
  }
190
191
3.61k
  int64_t select_offset() const {
192
3.61k
    return counter_pb_.select_offset();
193
3.61k
  }
194
195
3.93M
  bool reached_select_offset() const {
196
3.93M
    return !has_select_offset() || skip_count() >= select_offset();
197
3.93M
  }
198
199
  // Debug logging.
200
0
  string DebugString() const {
201
0
    return (string("\nQueryPB = {\n") + query_pb_.DebugString() + string ("\n};") +
202
0
            string("\nCounterPB = {\n") + counter_pb_.DebugString() + string("\n};"));
203
0
  }
204
205
  // Access to internal protobuf.
206
396
  const QLPagingStatePB& query_pb() const {
207
396
    return query_pb_;
208
396
  }
209
210
0
  const QLSelectRowCounterPB& counter_pb() const {
211
0
    return counter_pb_;
212
0
  }
213
214
33.5k
  uint64_t max_fetch_size() const {
215
33.5k
    return max_fetch_size_;
216
33.5k
  }
217
218
  // Users can indicate how many rows can be read at one time. If a SELECT statement has its own
219
  // LIMIT, the users' setting will be adjusted to the SELECT's LIMIT.
220
  void AdjustMaxFetchSizeToSelectLimit();
221
222
 private:
223
  // Query paging state.
224
  // - Paging state to be exchanged with DocDB and User.
225
  // - When loading data from users and DocDB, all information in the query_pb_ will be overwritten.
226
  //   All information are are needed for CQL processing must be kept separately from this variable.
227
  QLPagingStatePB query_pb_;
228
229
  // Row counter.
230
  // - Processed by CQL and should not be overwritten when loading status from users or docdb.
231
  // - Only top-level SELECT uses RowCounter.
232
  //   Example:
233
  //     SELECT * FROM <table> WHERE keys IN (SELECT keys FROM <index>)
234
  //   From user's point of view, only number of rows being read from <table> is meaningful, so
235
  //   clauses like LIMIT and OFFSET should be applied to top-level select row-count.
236
  // - NOTE:
237
  //   For fully-covered index query, the nested index query is promoted to top-level read node.
238
  //   In this scenarios, the INDEX becomes the primary table, and the counter for nested query
239
  //   is sent back to user.
240
  QLSelectRowCounterPB counter_pb_;
241
242
  // The maximum number of rows that user can receive at one time.
243
  //   max row number = MIN (<limit>, <page-size>)
244
  // If it is (-1), we fetch all of them.
245
  int64_t max_fetch_size_ = -1;
246
};
247
248
class TnodeContext {
249
 public:
250
  explicit TnodeContext(const TreeNode* tnode);
251
252
  ~TnodeContext();
253
254
  // Returns the tree node of the statement being executed.
255
19.9M
  const TreeNode* tnode() const {
256
19.9M
    return tnode_;
257
19.9M
  }
258
259
  // Access function for start_time and end_time.
260
11.5k
  const MonoTime& start_time() const {
261
11.5k
    return start_time_;
262
11.5k
  }
263
5.24M
  const MonoTime& end_time() const {
264
5.24M
    return end_time_;
265
5.24M
  }
266
5.24M
  void set_end_time(const MonoTime& end_time) {
267
5.24M
    end_time_ = end_time;
268
5.24M
  }
269
5.24M
  MonoDelta execution_time() const {
270
5.24M
    return end_time_ - start_time_;
271
5.24M
  }
272
273
  // Access function for op.
274
10.6M
  std::vector<client::YBqlOpPtr>& ops() {
275
10.6M
    return ops_;
276
10.6M
  }
277
187k
  const std::vector<client::YBqlOpPtr>& ops() const {
278
187k
    return ops_;
279
187k
  }
280
281
  // Add an operation.
282
5.17M
  void AddOperation(const client::YBqlOpPtr& op) {
283
5.17M
    ops_.push_back(op);
284
5.17M
  }
285
286
  // Does this statement have pending operations?
287
  bool HasPendingOperations() const;
288
289
  // Access function for rows result.
290
9.17M
  RowsResult::SharedPtr& rows_result() {
291
9.17M
    return rows_result_;
292
9.17M
  }
293
294
  // Append rows result that was sent back by DocDB to this node.
295
  CHECKED_STATUS AppendRowsResult(RowsResult::SharedPtr&& rows_result);
296
297
  // Create CQL paging state based on user's information.
298
  // When calling YugaByte, users provide all info in StatementParameters including paging state.
299
  QueryPagingState *CreateQueryState(const StatementParameters& user_params,
300
                                     bool is_top_level_select);
301
302
  // Clear paging state when the query reaches the end of scan.
303
  CHECKED_STATUS ClearQueryState();
304
305
15.6M
  QueryPagingState *query_state() {
306
15.6M
    return query_state_.get();
307
15.6M
  }
308
309
  // Access functions for row_count.
310
33.5k
  size_t row_count() const {
311
33.5k
    return row_count_;
312
33.5k
  }
313
314
  // Used for multi-partition selects (i.e. with 'IN' conditions on hash columns).
315
  // Called from Executor::FetchMoreRowsIfNeeded to check if request is finished.
316
8.09M
  uint64_t UnreadPartitionsRemaining() const {
317
8.09M
    return partitions_count_ - current_partition_index_;
318
8.09M
  }
319
320
  // Used for multi-partition selects (i.e. with 'IN' conditions on hash columns).
321
  // Initializes the current partition index and sets the corresponding hashed column values in the
322
  // request object so that it references the appropriate partition.
323
  // Called from Executor::ExecPTNode for PTSelectStmt.
324
  // E.g. for a query "h1 = 1 and h2 in (2,3) and h3 in (4,5) and h4 = 6" start_position 0:
325
  // this will set req->hashed_column_values() to [1, 2, 4, 6].
326
  void InitializePartition(QLReadRequestPB *req, bool continue_user_request);
327
328
  // Predicate for the completion of a partition read.
329
  bool FinishedReadingPartition();
330
331
  // Used for multi-partition selects (i.e. with 'IN' conditions on hash columns).
332
  // Increments the current partition index and updates the corresponding hashed column values in
333
  // passed request object so that it references the appropriate partition.
334
  // Called from Executor::FetchMoreRowsIfNeeded.
335
  // E.g. for a query "h1 = 1 and h2 in (2,3) and h3 in (4,5) and h4 = 6" partition index 2:
336
  // this will do, index: 2 -> 3 and hashed_column_values: [1, 3, 4, 6] -> [1, 3, 5, 6].
337
  void AdvanceToNextPartition(QLReadRequestPB *req);
338
339
2.17k
  std::vector<std::vector<QLExpressionPB>>& hash_values_options() {
340
2.17k
    if (!hash_values_options_) {
341
1.07k
      hash_values_options_.emplace();
342
1.07k
    }
343
2.17k
    return *hash_values_options_;
344
2.17k
  }
345
346
282
  uint64_t current_partition_index() const {
347
282
    return current_partition_index_;
348
282
  }
349
350
1.07k
  void set_partitions_count(const uint64_t count) {
351
1.07k
    partitions_count_ = count;
352
1.07k
  }
353
354
  // Access functions for child tnode context.
355
  TnodeContext* AddChildTnode(const TreeNode* tnode);
356
357
10.6M
  TnodeContext* child_context() {
358
10.6M
    return child_context_.get();
359
10.6M
  }
360
0
  const TnodeContext* child_context() const {
361
0
    return child_context_.get();
362
0
  }
363
364
  // Allocate and prepare parent node for reading keys from nested query.
365
  void SetUncoveredSelectOp(const client::YBqlReadOpPtr& select_op);
366
367
  // Access functions for uncovered select op template and primary keys.
368
1.52k
  const client::YBqlReadOpPtr& uncovered_select_op() const {
369
1.52k
    return uncovered_select_op_;
370
1.52k
  }
371
1.52k
  QLRowBlock* keys() {
372
1.52k
    return keys_.get();
373
1.52k
  }
374
375
  // Compose the final result (rows_result_) which will be sent to users.
376
  // - Data content: Already in rows_result_
377
  // - Read-response paging state: query_state_::query_pb_
378
  // - Row counters: query_state_::counter_pb_
379
  //
380
  // NOTE:
381
  // 1. For primary-indexed or sequential scan SELECT.
382
  //    - Data is read from primary table.
383
  //    - User paging state = { QueryPagingState::query_pb_ }
384
  //    - DocDB paging state = { QueryPagingState::query_pb_ }
385
  //
386
  // 2. Full-covered secondary-indexed SELECT
387
  //    - Data is read from secondary table.
388
  //    - Users paging state = { Nested QueryPagingState::query_pb_ }
389
  //    - DocDB paging state = { Nested QueryPagingState::query_pb_ }
390
  //
391
  // 3. Partial-covered secondary-indexed SELECT
392
  //    - Primary key is read from INDEX table (nested query).
393
  //    - Data is read from PRIMARY table (top level query).
394
  //    - When construct user paging state, we compose two paging states into one.
395
  //      The read state = nested query read state.
396
  //      The counter state = top-level query counter state.
397
  //      User paging state = { Nested QueryPagingState::query_pb_,
398
  //                            Top-Level QueryPagingState::counter_pb_ }
399
  CHECKED_STATUS ComposeRowsResultForUser(const TreeNode* child_select_node, bool for_new_batches);
400
401
0
  const boost::optional<uint32_t>& hash_code_from_partition_key_ops() {
402
0
    return hash_code_from_partition_key_ops_;
403
0
  }
404
405
0
  const boost::optional<uint32_t>& max_hash_code_from_partition_key_ops() {
406
0
    return max_hash_code_from_partition_key_ops_;
407
0
  }
408
409
33
  void set_hash_code_from_partition_key_ops(uint32_t hash_code) {
410
33
    hash_code_from_partition_key_ops_ = hash_code;
411
33
  }
412
413
23
  void set_max_hash_code_from_partition_key_ops(uint32_t max_hash_code) {
414
23
    max_hash_code_from_partition_key_ops_ = max_hash_code;
415
23
  }
416
417
 private:
418
  // Tree node of the statement being executed.
419
  const TreeNode* tnode_ = nullptr;
420
421
  // Execution start and end time.
422
  const MonoTime start_time_;
423
  MonoTime end_time_;
424
425
  // Read/write operations to execute.
426
  std::vector<client::YBqlOpPtr> ops_;
427
428
  // Accumulated number of rows fetched by the statement.
429
  size_t row_count_ = 0;
430
431
  // For multi-partition selects (e.g. selects with 'IN' condition on hash cols) we hold the options
432
  // for each hash column (starting from first 'IN') as we iteratively query each partition.
433
  // e.g. for a query "h1 = 1 and h2 in (2,3) and h3 in (4,5) and h4 = 6".
434
  //  hash_values_options_ = [[2, 3], [4, 5], [6]]
435
  //  partitions_count_ = 4 (i.e. [2,4,6], [2,5,6], [3,4,6], [3,5,6]).
436
  //  current_partition_index_ starts from 0 unless set in the paging state.
437
  boost::optional<std::vector<std::vector<QLExpressionPB>>> hash_values_options_;
438
  uint64_t partitions_count_ = 0;
439
  uint64_t current_partition_index_ = 0;
440
441
  // Rows result of this statement tnode for DML statements.
442
  RowsResult::SharedPtr rows_result_;
443
444
  // Read paging state for each query including nested query.
445
  // - Only SELECT statement has a query_state_.
446
  // - The rest of commands has a NULL query_state_.
447
  QueryPagingState::UniPtr query_state_;
448
449
  // Child context for nested statement.
450
  std::unique_ptr<TnodeContext> child_context_;
451
452
  // Select op template and primary keys for fetching from indexed table in an uncovered query.
453
  client::YBqlReadOpPtr uncovered_select_op_;
454
  std::unique_ptr<QLRowBlock> keys_;
455
456
  boost::optional<uint32_t> hash_code_from_partition_key_ops_;
457
  boost::optional<uint32_t> max_hash_code_from_partition_key_ops_;
458
};
459
460
// The context for execution of a statement. Inside the statement parse tree, there may be one or
461
// more statement tnodes to be executed.
462
class ExecContext : public ProcessContextBase {
463
 public:
464
  //------------------------------------------------------------------------------------------------
465
  // Public types.
466
  typedef std::unique_ptr<ExecContext> UniPtr;
467
  typedef std::unique_ptr<const ExecContext> UniPtrConst;
468
469
  //------------------------------------------------------------------------------------------------
470
  // Constructor & destructor.
471
472
  // Constructs an execution context to execute a statement. The context saves references to the
473
  // parse tree and parameters.
474
  ExecContext(const ParseTree& parse_tree, const StatementParameters& params);
475
  virtual ~ExecContext();
476
477
  // Returns the statement string being executed.
478
  const std::string& stmt() const override;
479
480
  // Access function for parse_tree and params.
481
5.27M
  const ParseTree& parse_tree() const {
482
5.27M
    return parse_tree_;
483
5.27M
  }
484
22.5M
  const StatementParameters& params() const {
485
22.5M
    return params_;
486
22.5M
  }
487
488
  // Add a statement tree node to be executed.
489
  TnodeContext* AddTnode(const TreeNode *tnode);
490
491
  // Return the tnode contexts being executed.
492
15.5M
  std::list<TnodeContext>& tnode_contexts() {
493
15.5M
    return tnode_contexts_;
494
15.5M
  }
495
496
  //------------------------------------------------------------------------------------------------
497
  // Start a distributed transaction.
498
  CHECKED_STATUS StartTransaction(
499
      IsolationLevel isolation_level, QLEnv* ql_env, Rescheduler* rescheduler);
500
501
  // Is a transaction currently in progress?
502
28.5M
  bool HasTransaction() const {
503
28.5M
    return transaction_ != nullptr;
504
28.5M
  }
505
506
  // Returns the start time of the transaction.
507
32.7k
  const MonoTime& transaction_start_time() const {
508
32.7k
    return transaction_start_time_;
509
32.7k
  }
510
511
  // Prepare a child distributed transaction.
512
  CHECKED_STATUS PrepareChildTransaction(CoarseTimePoint deadline, ChildTransactionDataPB* data);
513
514
  // Apply the result of a child distributed transaction.
515
  CHECKED_STATUS ApplyChildTransactionResult(const ChildTransactionResultPB& result);
516
517
  // Commit the current distributed transaction.
518
  void CommitTransaction(CoarseTimePoint deadline, client::CommitCallback callback);
519
520
  // Abort the current distributed transaction.
521
  void AbortTransaction();
522
523
  // Return the transactional session of the statement.
524
383k
  client::YBSessionPtr transactional_session() {
525
266
    DCHECK(transaction_ && transactional_session_) << "transaction missing in this statement";
526
383k
    return transactional_session_;
527
383k
  }
528
529
  // Does this statement have pending operations?
530
  bool HasPendingOperations() const;
531
532
  //------------------------------------------------------------------------------------------------
533
15.8M
  client::Restart restart() const {
534
15.8M
    return restart_;
535
15.8M
  }
536
537
5.08M
  int64_t num_retries() const {
538
5.08M
    return num_retries_;
539
5.08M
  }
540
541
  // Reset this ExecContext.
542
  void Reset(client::Restart restart, Rescheduler* rescheduler);
543
544
 private:
545
  // Statement parse tree to execute and parameters to execute with.
546
  const ParseTree& parse_tree_;
547
  const StatementParameters& params_;
548
549
  // Should this statement be restarted?
550
  client::Restart restart_ = client::Restart::kFalse;
551
552
  // Contexts to execute statement tnodes.
553
  std::list<TnodeContext> tnode_contexts_;
554
555
  // Transaction and session to apply transactional write operations in and the start time.
556
  client::YBTransactionPtr transaction_;
557
  client::YBSessionPtr transactional_session_;
558
  MonoTime transaction_start_time_;
559
560
  // The number of times this statement has been retried.
561
  int64_t num_retries_ = 0;
562
};
563
564
}  // namespace ql
565
}  // namespace yb
566
567
#endif  // YB_YQL_CQL_QL_EXEC_EXEC_CONTEXT_H_