YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/yql/pggate/pg_doc_op.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
#ifndef YB_YQL_PGGATE_PG_DOC_OP_H_
16
#define YB_YQL_PGGATE_PG_DOC_OP_H_
17
18
#include <deque>
19
20
#include <boost/optional.hpp>
21
22
#include "yb/util/locks.h"
23
#include "yb/client/yb_op.h"
24
25
#include "yb/yql/pggate/pg_gate_fwd.h"
26
#include "yb/yql/pggate/pg_op.h"
27
#include "yb/yql/pggate/pg_session.h"
28
29
namespace yb {
30
namespace pggate {
31
32
class PgTuple;
33
34
YB_STRONGLY_TYPED_BOOL(RequestSent);
35
36
//--------------------------------------------------------------------------------------------------
37
// PgDocResult represents a batch of rows in ONE reply from tablet servers.
38
class PgDocResult {
39
 public:
40
  explicit PgDocResult(rpc::SidecarPtr&& data);
41
  PgDocResult(rpc::SidecarPtr&& data, std::list<int64_t>&& row_orders);
42
  ~PgDocResult();
43
44
  PgDocResult(const PgDocResult&) = delete;
45
  PgDocResult& operator=(const PgDocResult&) = delete;
46
47
  // Get the order of the next row in this batch.
48
  int64_t NextRowOrder();
49
50
  // End of this batch.
51
21.4M
  bool is_eof() const {
52
21.4M
    return row_count_ == 0 || row_iterator_.empty();
53
21.4M
  }
54
55
  // Get the postgres tuple from this batch.
56
  CHECKED_STATUS WritePgTuple(const std::vector<PgExpr*>& targets, PgTuple *pg_tuple,
57
                              int64_t *row_order);
58
59
  // Get system columns' values from this batch.
60
  // Currently, we only have ybctids, but there could be more.
61
  CHECKED_STATUS ProcessSystemColumns();
62
63
  // Update the reservoir with ybctids from this batch.
64
  // The update is expected to be sparse, so ybctids come as index/value pairs.
65
  CHECKED_STATUS ProcessSparseSystemColumns(std::string *reservoir);
66
67
  // Access function to ybctids value in this batch.
68
  // Sys columns must be processed before this function is called.
69
1.72k
  const vector<Slice>& ybctids() const {
70
0
    DCHECK(syscol_processed_) << "System columns are not yet setup";
71
1.72k
    return ybctids_;
72
1.72k
  }
73
74
  // Row count in this batch.
75
0
  int64_t row_count() const {
76
0
    return row_count_;
77
0
  }
78
79
 private:
80
  // Data selected from DocDB.
81
  rpc::SidecarPtr data_;
82
83
  // Iterator on "data_" from row to row.
84
  Slice row_iterator_;
85
86
  // The row number of only this batch.
87
  int64_t row_count_ = 0;
88
89
  // The indexing order of the row in this batch.
90
  // These order values help to identify the row order across all batches.
91
  std::list<int64_t> row_orders_;
92
93
  // System columns.
94
  // - ybctids_ contains pointers to the buffers "data_".
95
  // - System columns must be processed before these fields have any meaning.
96
  vector<Slice> ybctids_;
97
  bool syscol_processed_ = false;
98
};
99
100
//--------------------------------------------------------------------------------------------------
101
// Doc operation API
102
// Classes
103
// - PgDocOp: Shared functionalities among all ops, mostly just RPC calls to tablet servers.
104
// - PgDocReadOp: Definition for data & method members to be used in READ operation.
105
// - PgDocWriteOp: Definition for data & method members to be used in WRITE operation.
106
// - PgDocResult: Definition data holder before they are passed to Postgres layer.
107
//
108
// Processing Steps
109
// (1) Collecting Data:
110
//     PgGate collects data from Posgres and write to a "PgDocOp::Template".
111
//
112
// (2) Create operators:
113
//     When no optimization is applied, the "template_op" is executed as is. When an optimization
114
//     is chosen, PgDocOp will clone the template to populate operators and kept them in vector
115
//     "pgsql_ops_". When an op executes arguments, it sends request and reads replies from servers.
116
//
117
//     * Vector "pgsql_ops_" is of fixed size for the entire execution, and its contents (YBPgsqlOp
118
//       shared_ptrs) also remain for the entire execution.
119
//     * There is a LIMIT on how many pgsql-op can be cloned. If the number of requests / arguments
120
//       are higher than the LIMIT, some requests will have to wait in queue until the execution
121
//       of precedent arguments are completed.
122
//     * After an argument input is executed, its associated YBPgsqlOp will be reused to execute
123
//       a new set of arguments. We don't clone new ones for new arguments.
124
//     * When a YBPgsqlOp is reused, its YBPgsqlOp::ProtobufRequest will be updated appropriately
125
//       with new arguments.
126
//     * NOTE: Some operators in "pgsql_ops_" might not be active (no arguments) at a given time
127
//       of execution. For example, some ops might complete their execution while others have
128
//       paging state and are sent again to table server.
129
//
130
// (3) SendRequest:
131
//     PgSession API requires contiguous array of operators. For this reason, before sending the
132
//     pgsql_ops_ is soreted to place active ops first, and all inactive ops are place at the end.
133
//     For example,
134
//        PgSession::RunAsync(pgsql_ops_.data(), active_op_count)
135
//
136
// (4) ReadResponse:
137
//     Response are written to a local cache PgDocResult.
138
//
139
// This API has several sets of methods and attributes for different purposes.
140
// (1) Build request.
141
//  This section collect information and data from PgGate API.
142
//  * Attributes
143
//    - relation_id_: Table to be operated on.
144
//    - template_op_ of type YBPgsqlReadOp and YBPgsqlWriteOp.
145
//      This object contains statement descriptions and expression values from users.
146
//      All user-provided arguments are kept in this attributes.
147
//  * Methods
148
//    - Class constructors.
149
//
150
// (2) Constructing protobuf request.
151
//  This section populates protobuf requests using the collected information in "template_op_".
152
//  - Without optimization, the protobuf request in "template_op_" will be used .
153
//  - With parallel optimization, multiple protobufs are constructed by cloning template into many
154
//    operators. How the execution are subdivided is depending on the parallelism method.
155
//  NOTE Whenever we support PREPARE(stmt), we'd stop processing at after this step for PREPARE.
156
//
157
//  * Attributes
158
//    - YBPgsqlOp pgsql_ops_: Contains all protobuf requests to be sent to tablet servers.
159
//  * Methods
160
//    - When there isn't any optimization, template_op_ is used.
161
//        pgsql_ops_[0] = template_op_
162
//    - CreateRequests()
163
//    - ClonePgsqlOps() Clone template_op_ into one or more ops.
164
//    - PopulateParallelSelectOps() Parallel processing of aggregate requests or requests with
165
//      WHERE expressions filtering rows in DocDB.
166
//      The same requests are constructed for each tablet server.
167
//    - PopulateNextHashPermutationOps() Parallel processing SELECT by hash conditions.
168
//      Hash permutations will be group into different request based on their hash_codes.
169
//    - PopulateDmlByYbctidOps() Parallel processing SELECT by ybctid values.
170
//      Ybctid values will be group into different request based on their hash_codes.
171
//      This function is a bit different from other formulating function because it is used for an
172
//      internal request within PgGate. Other populate functions are used for external requests
173
//      from Postgres layer via PgGate API.
174
//
175
// (3) Execution
176
//  This section exchanges RPC calls with tablet servers.
177
//  * Attributes
178
//    - active_op_counts_: Number of active operators in vector "pgsql_ops_".
179
//        Exec/active op range = pgsql_ops_[0, active_op_count_)
180
//        Inactive op range = pgsql_ops_[active_op_count_, total_count)
181
//      The vector pgsql_ops_ is fixed sized, can have inactive operators as operators are not
182
//      completing execution at the same time.
183
//  * Methods
184
//    - ExecuteInit()
185
//    - Execute() Driver for all RPC related effort.
186
//    - SendRequest() Send request for active operators to tablet server using YBPgsqlOp.
187
//        RunAsync(pgsql_ops_.data(), active_op_count_)
188
//    - ProcessResponse() Get response from tablet server using YBPgsqlOp.
189
//    - MoveInactiveOpsOutside() Sort pgsql_ops_ to move inactive operators outside of exec range.
190
//
191
// (4) Return result
192
//  This section return result via PgGate API to postgres.
193
//  * Attributes
194
//    - Objects of class PgDocResult
195
//    - rows_affected_count_: Number of rows that was operated by this doc_op.
196
//  * Methods
197
//    - GetResult()
198
//    - GetRowsAffectedCount()
199
//
200
// TODO(dmitry / neil) Allow sending active requests and receive their response one at a time.
201
//
202
// To process data in parallel, the operators must be able to run independently from one another.
203
// However, currently operators are executed in batches and together even though they belong to
204
// different partitions and interact with different tablet servers.
205
//--------------------------------------------------------------------------------------------------
206
207
class PgDocOp : public std::enable_shared_from_this<PgDocOp> {
208
 public:
209
  // Public types.
210
  typedef std::shared_ptr<PgDocOp> SharedPtr;
211
  typedef std::shared_ptr<const PgDocOp> SharedPtrConst;
212
213
  typedef std::unique_ptr<PgDocOp> UniPtr;
214
  typedef std::unique_ptr<const PgDocOp> UniPtrConst;
215
216
  // Constructors & Destructors.
217
  PgDocOp(const PgSession::ScopedRefPtr& pg_session,
218
          PgTable* table,
219
          const PgObjectId& relation_id = PgObjectId());
220
  virtual ~PgDocOp();
221
222
  // Initialize doc operator.
223
  virtual CHECKED_STATUS ExecuteInit(const PgExecParameters *exec_params);
224
225
  const PgExecParameters& ExecParameters() const;
226
227
  // Execute the op. Return true if the request has been sent and is awaiting the result.
228
  virtual Result<RequestSent> Execute(bool force_non_bufferable = false);
229
230
  // Instruct this doc_op to abandon execution and querying data by setting end_of_data_ to 'true'.
231
  // - This op will not send request to tablet server.
232
  // - This op will return empty result-set when being requested for data.
233
113
  void AbandonExecution() {
234
113
    end_of_data_ = true;
235
113
  }
236
237
  // Get the result of the op. No rows will be added to rowsets in case end of data reached.
238
  CHECKED_STATUS GetResult(std::list<PgDocResult> *rowsets);
239
  Result<int32_t> GetRowsAffectedCount() const;
240
241
  // This operation is requested internally within PgGate, and that request does not go through
242
  // all the steps as other operation from Postgres thru PgDocOp. This is used to create requests
243
  // for the following select.
244
  //   SELECT ... FROM <table> WHERE ybctid IN (SELECT base_ybctids from INDEX)
245
  // After ybctids are queried from INDEX, PgGate will call "PopulateDmlByYbctidOps" to create
246
  // operators to fetch rows whose rowids equal queried ybctids.
247
  CHECKED_STATUS PopulateDmlByYbctidOps(const std::vector<Slice>& ybctids);
248
249
590k
  bool has_out_param_backfill_spec() {
250
590k
    return !out_param_backfill_spec_.empty();
251
590k
  }
252
253
257
  const char* out_param_backfill_spec() {
254
257
    return out_param_backfill_spec_.c_str();
255
257
  }
256
257
0
  bool end_of_data() const {
258
0
    return end_of_data_;
259
0
  }
260
261
  virtual bool IsWrite() const = 0;
262
263
  CHECKED_STATUS CreateRequests();
264
265
 protected:
266
  uint64_t& GetReadTime();
267
268
  // Populate Protobuf requests using the collected informtion for this DocDB operator.
269
  virtual Result<bool> DoCreateRequests() = 0;
270
271
  virtual CHECKED_STATUS DoPopulateDmlByYbctidOps(const std::vector<Slice>& ybctids) = 0;
272
273
  // Create operators.
274
  // - Each operator is used for one request.
275
  // - When parallelism by partition is applied, each operator is associated with one partition,
276
  //   and each operator has a batch of arguments that belong to that partition.
277
  //   * The higher the number of partition_count, the higher the parallelism level.
278
  //   * If (partition_count == 1), only one operator is needed for the entire partition range.
279
  //   * If (partition_count > 1), each operator is used for a specific partition range.
280
  //   * This optimization is used by
281
  //       PopulateDmlByYbctidOps()
282
  //       PopulateParallelSelectOps()
283
  // - When parallelism by arguments is applied, each operator has only one argument.
284
  //   When tablet server will run the requests in parallel as it assigned one thread per request.
285
  //       PopulateNextHashPermutationOps()
286
  CHECKED_STATUS ClonePgsqlOps(size_t op_count);
287
288
  // Only active operators are kept in the active range [0, active_op_count_)
289
  // - Not execute operators that are outside of range [0, active_op_count_).
290
  // - Sort the operators in "pgsql_ops_" to move "inactive" operators to the end of the list.
291
  void MoveInactiveOpsOutside();
292
293
  // Clone READ or WRITE "template_op_" into new operators.
294
  virtual PgsqlOpPtr CloneFromTemplate() = 0;
295
296
  // Process the result set in server response.
297
  Result<std::list<PgDocResult>> ProcessResponseResult();
298
299
  void SetReadTime();
300
301
 private:
302
  CHECKED_STATUS SendRequest(bool force_non_bufferable);
303
304
  virtual CHECKED_STATUS SendRequestImpl(bool force_non_bufferable);
305
306
  Result<std::list<PgDocResult>> ProcessResponse(const Status& exec_status);
307
308
  virtual Result<std::list<PgDocResult>> ProcessResponseImpl() = 0;
309
310
  CHECKED_STATUS CompleteRequests();
311
312
  //----------------------------------- Data Members -----------------------------------------------
313
 protected:
314
  // Session control.
315
  PgSession::ScopedRefPtr pg_session_;
316
317
  // Operation time. This time is set at the start and must stay the same for the lifetime of the
318
  // operation to ensure that it is operating on one snapshot.
319
  uint64_t read_time_ = 0;
320
321
  // Target table.
322
  PgTable& table_;
323
  PgObjectId relation_id_;
324
325
  // Exec control parameters.
326
  PgExecParameters exec_params_;
327
328
  // Suppress sending new request after processing response.
329
  // Next request will be sent in case upper level will ask for additional data.
330
  bool suppress_next_result_prefetching_ = false;
331
332
  // Populated protobuf request.
333
  std::vector<PgsqlOpPtr> pgsql_ops_;
334
335
  // Number of active operators in the pgsql_ops_ list.
336
  size_t active_op_count_ = 0;
337
338
  // Indicator for completing all request populations.
339
  bool request_population_completed_ = false;
340
341
  // If true, all data for each batch must be collected before PgGate gets the reply.
342
  // NOTE:
343
  // - Currently, PgSession's default behavior is to get all responses in a batch together.
344
  // - We set this flag only to prevent future optimization where requests & their responses to
345
  //   and from different tablet servers are sent and received independently. That optimization
346
  //   should only be done when "wait_for_batch_completion_ == false"
347
  bool wait_for_batch_completion_ = true;
348
349
  // Future object to fetch a response from DocDB after sending a request.
350
  // Object's valid() method returns false in case no request is sent
351
  // or sent request was buffered by the session.
352
  // Only one RunAsync() can be called to sent to DocDB at a time.
353
  PerformFuture response_;
354
355
  // Executed row count.
356
  int32_t rows_affected_count_ = 0;
357
358
  // Whether all requested data by the statement has been received or there's a run-time error.
359
  bool end_of_data_ = false;
360
361
  // The order number of each request when batching arguments.
362
  // Currently, this is used for query by YBCTID.
363
  // - Each pgsql_op has a batch of ybctids selected from INDEX.
364
  // - The order of resulting rows should match with the order of queried ybctids.
365
  // - Example:
366
  //   Suppose we got from INDEX table
367
  //     { ybctid_1, ybctid_2, ybctid_3, ybctid_4, ybctid_5, ybctid_6, ybctid_7 }
368
  //
369
  //   Now pgsql_op are constructed as the following, one op per partition.
370
  //     pgsql_op <partition 1> (ybctid_1, ybctid_3, ybctid_4)
371
  //     pgsql_op <partition 2> (ybctid_2, ybctid_6)
372
  //     pgsql_op <partition 2> (ybctid_5, ybctid_7)
373
  //
374
  //  These respective ybctids are stored in batch_ybctid_ also.
375
  //  In other words,
376
  //     batch_ybctid_[partition 1] contains  (ybctid_1, ybctid_3, ybctid_4)
377
  //     batch_ybctid_[partition 2] contains  (ybctid_2, ybctid_6)
378
  //     batch_ybctid_[partition 3] contains  (ybctid_5, ybctid_7)
379
  //
380
  //   After getting the rows of data from pgsql, the rows must be then ordered from 1 thru 7.
381
  //   To do so, for each pgsql_op we kept an array of orders, batch_row_orders_.
382
  //   For the above pgsql_ops_, the orders would be cached as the following.
383
  //     vector orders { partition 1: list ( 1, 3, 4 ),
384
  //                     partition 2: list ( 2, 6 ),
385
  //                     partition 3: list ( 5, 7 ) }
386
  //
387
  //   When the "pgsql_ops_" elements are sorted and swapped order, the "batch_row_orders_"
388
  //   must be swaped also.
389
  //     std::swap ( pgsql_ops_[1], pgsql_ops_[3])
390
  //     std::swap ( batch_row_orders_[1], batch_row_orders_[3] )
391
  std::vector<std::list<int64_t>> batch_row_orders_;
392
393
  // This counter is used to maintain the row order when the operator sends requests in parallel
394
  // by partition. Currently only query by YBCTID uses this variable.
395
  int64_t batch_row_ordering_counter_ = 0;
396
397
  // Parallelism level.
398
  // - This is the maximum number of read/write requests being sent to servers at one time.
399
  // - When it is 1, there's no optimization. Available requests is executed one at a time.
400
  size_t parallelism_level_ = 1;
401
402
  // Output parameter of the execution.
403
  string out_param_backfill_spec_;
404
405
 private:
406
  // Result set either from selected or returned targets is cached in a list of strings.
407
  // Querying state variables.
408
  Status exec_status_ = Status::OK();
409
};
410
411
//--------------------------------------------------------------------------------------------------
412
413
class PgDocReadOp : public PgDocOp {
414
 public:
415
  // Public types.
416
  typedef std::shared_ptr<PgDocReadOp> SharedPtr;
417
  typedef std::shared_ptr<const PgDocReadOp> SharedPtrConst;
418
419
  typedef std::unique_ptr<PgDocReadOp> UniPtr;
420
  typedef std::unique_ptr<const PgDocReadOp> UniPtrConst;
421
422
  // Constructors & Destructors.
423
  PgDocReadOp(
424
      const PgSession::ScopedRefPtr& pg_session, PgTable* table,
425
      PgsqlReadOpPtr read_op);
426
427
  CHECKED_STATUS ExecuteInit(const PgExecParameters *exec_params) override;
428
429
  // Row sampler collects number of live and dead rows it sees.
430
  CHECKED_STATUS GetEstimatedRowCount(double *liverows, double *deadrows);
431
432
0
  bool IsWrite() const override {
433
0
    return false;
434
0
  }
435
436
  CHECKED_STATUS DoPopulateDmlByYbctidOps(const std::vector<Slice>& ybctids) override;
437
438
 private:
439
  // Create protobuf requests using template_op_.
440
  Result<bool> DoCreateRequests() override;
441
442
  // Create operators by partition.
443
  // - Optimization for statement
444
  //     SELECT xxx FROM <table> WHERE ybctid IN (SELECT ybctid FROM INDEX)
445
  // - After being queried from inner select, ybctids are used for populate request for outer query.
446
  CHECKED_STATUS InitializeYbctidOperators();
447
448
  // Create operators by partition arguments.
449
  // - Optimization for statement:
450
  //     SELECT ... WHERE <hash-columns> IN <value-lists>
451
  // - If partition column binds are defined, partition_column_values field of each operation
452
  //   is set to be the next permutation.
453
  // - When an operator is assigned a hash permutation, it is marked as active to be executed.
454
  // - When an operator completes the execution, it is marked as inactive and available for the
455
  //   exection of the next hash permutation.
456
  Result<bool> PopulateNextHashPermutationOps();
457
  CHECKED_STATUS InitializeHashPermutationStates();
458
459
  // Create operators by partitions.
460
  // - Optimization for aggregating or filtering requests.
461
  Result<bool> PopulateParallelSelectOps();
462
463
  // Create one sampling operator per partition and arrange their execution in random order
464
  Result<bool> PopulateSamplingOps();
465
466
  // Set partition boundaries to a given partition.
467
  CHECKED_STATUS SetScanPartitionBoundary();
468
469
  // Process response from DocDB.
470
  Result<std::list<PgDocResult>> ProcessResponseImpl() override;
471
472
  // Process response read state from DocDB.
473
  CHECKED_STATUS ProcessResponseReadStates();
474
475
  // Reset pgsql operators before reusing them with new arguments / inputs from Postgres.
476
  CHECKED_STATUS ResetInactivePgsqlOps();
477
478
  // Analyze options and pick the appropriate prefetch limit.
479
  void SetRequestPrefetchLimit();
480
481
  // Set the backfill_spec field of our read request.
482
  void SetBackfillSpec();
483
484
  // Set the row_mark_type field of our read request based on our exec control parameter.
485
  void SetRowMark();
486
487
  // Set the read_time for our read request based on our exec control parameter.
488
  void SetReadTime();
489
490
  // Clone the template into actual requests to be sent to server.
491
1.45M
  PgsqlOpPtr CloneFromTemplate() override {
492
1.45M
    return read_op_->DeepCopy();
493
1.45M
  }
494
495
  // Get the read_req for a specific operation index from pgsql_ops_.
496
  PgsqlReadRequestPB& GetReadReq(size_t op_index);
497
498
  // Re-format the request when connecting to older server during rolling upgrade.
499
  void FormulateRequestForRollingUpgrade(PgsqlReadRequestPB *read_req);
500
501
  //----------------------------------- Data Members -----------------------------------------------
502
503
  // Template operation, used to fill in pgsql_ops_ by either assigning or cloning.
504
  PgsqlReadOpPtr read_op_;
505
506
  // While sampling is in progress, number of scanned row is accumulated in this variable.
507
  // After completion the value is extrapolated to account for not scanned partitions and estimate
508
  // total number of rows in the table.
509
  double sample_rows_ = 0;
510
511
  // Used internally for PopulateNextHashPermutationOps to keep track of which permutation should
512
  // be used to construct the next read_op.
513
  // Is valid as long as request_population_completed_ is false.
514
  //
515
  // Example:
516
  // For a query clause "h1 = 1 AND h2 IN (2,3) AND h3 IN (4,5,6) AND h4 = 7",
517
  // there are 1*2*3*1 = 6 possible permutation.
518
  // As such, this field will take on values 0 through 5.
519
  int total_permutation_count_ = 0;
520
  int next_permutation_idx_ = 0;
521
522
  // Used internally for PopulateNextHashPermutationOps to holds all partition expressions.
523
  // Elements correspond to a hash columns, in the same order as they were defined
524
  // in CREATE TABLE statement.
525
  // This is somewhat similar to what hash_values_options_ in CQL is used for.
526
  //
527
  // Example:
528
  // For a query clause "h1 = 1 AND h2 IN (2,3) AND h3 IN (4,5,6) AND h4 = 7",
529
  // this will be initialized to [[1], [2, 3], [4, 5, 6], [7]]
530
  std::vector<std::vector<const PgsqlExpressionPB*>> partition_exprs_;
531
};
532
533
//--------------------------------------------------------------------------------------------------
534
535
class PgDocWriteOp : public PgDocOp {
536
 public:
537
  // Public types.
538
  typedef std::shared_ptr<PgDocWriteOp> SharedPtr;
539
  typedef std::shared_ptr<const PgDocWriteOp> SharedPtrConst;
540
541
  typedef std::unique_ptr<PgDocWriteOp> UniPtr;
542
  typedef std::unique_ptr<const PgDocWriteOp> UniPtrConst;
543
544
  // Constructors & Destructors.
545
  PgDocWriteOp(const PgSession::ScopedRefPtr& pg_session,
546
               PgTable* table,
547
               const PgObjectId& relation_id,
548
               PgsqlWriteOpPtr write_op);
549
550
  // Set write time.
551
  void SetWriteTime(const HybridTime& write_time);
552
553
0
  bool IsWrite() const override {
554
0
    return true;
555
0
  }
556
557
 private:
558
  // Process response implementation.
559
  Result<std::list<PgDocResult>> ProcessResponseImpl() override;
560
561
  // Create protobuf requests using template_op (write_op).
562
  Result<bool> DoCreateRequests() override;
563
564
  // For write ops, we are not yet batching ybctid from index query.
565
  // TODO(neil) This function will be implemented when we push down sub-query inside WRITE ops to
566
  // the proxy layer. There's many scenarios where this optimization can be done.
567
0
  CHECKED_STATUS DoPopulateDmlByYbctidOps(const std::vector<Slice>& ybctids) override {
568
0
    LOG(FATAL) << "Not yet implemented";
569
0
    return Status::OK();
570
0
  }
571
572
  // Get WRITE operator for a specific operator index in pgsql_ops_.
573
  PgsqlWriteRequestPB& GetWriteOp(int op_index);
574
575
  // Clone user data from template to actual protobuf requests.
576
0
  PgsqlOpPtr CloneFromTemplate() override {
577
0
    return write_op_->DeepCopy();
578
0
  }
579
580
  //----------------------------------- Data Members -----------------------------------------------
581
  // Template operation all write ops.
582
  PgsqlWriteOpPtr write_op_;
583
};
584
585
}  // namespace pggate
586
}  // namespace yb
587
588
#endif // YB_YQL_PGGATE_PG_DOC_OP_H_