YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/common/ql_scanspec.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
//
14
// This file contains QLScanSpec that implements a QL scan specification.
15
16
#include "yb/common/ql_scanspec.h"
17
18
#include "yb/common/pgsql_protocol.pb.h"
19
#include "yb/common/ql_expr.h"
20
#include "yb/common/ql_value.h"
21
#include "yb/common/schema.h"
22
23
namespace yb {
24
25
using std::unordered_map;
26
using std::pair;
27
using std::vector;
28
29
//-------------------------------------- QL scan range --------------------------------------
30
QLScanRange::QLScanRange(const Schema& schema, const QLConditionPB& condition)
31
81.7k
    : schema_(schema) {
32
33
  // If there is no range column, return.
34
81.7k
  if (schema_.num_range_key_columns() == 0) {
35
2.09k
    return;
36
2.09k
  }
37
38
  // Initialize the lower/upper bounds of each range column to null to mean it is unbounded.
39
79.6k
  ranges_.reserve(schema_.num_range_key_columns());
40
261k
  for (size_t i = 0; i < schema.num_key_columns(); i++) {
41
181k
    if (schema.is_range_column(i)) {
42
145k
      ranges_.emplace(schema.column_id(i), QLRange());
43
145k
    }
44
181k
  }
45
46
  // Check if there is a range column referenced in the operands.
47
79.6k
  const auto& operands = condition.operands();
48
79.6k
  bool has_range_column = false;
49
88.1k
  for (const auto& operand : operands) {
50
88.1k
    if (operand.expr_case() == QLExpressionPB::ExprCase::kColumnId &&
51
43.0k
        schema.is_range_column(ColumnId(operand.column_id()))) {
52
40.9k
      has_range_column = true;
53
40.9k
      break;
54
40.9k
    }
55
88.1k
  }
56
57
79.6k
  switch (condition.op()) {
58
59
0
#define QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr)                       \
60
40.9k
      CHECK_EQ(operands.size(), 2);                                                     \
61
40.9k
      QLExpressionPB const* col_expr = nullptr;                                        \
62
40.9k
      QLExpressionPB const* val_expr = nullptr;                                        \
63
40.9k
      if (operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kColumnId &&        \
64
40.8k
          operands.Get(1).expr_case() == QLExpressionPB::ExprCase::kValue) {           \
65
40.8k
        col_expr = &operands.Get(0);                                                    \
66
40.8k
        val_expr = &operands.Get(1);                                                    \
67
46
      } else if (operands.Get(1).expr_case() == QLExpressionPB::ExprCase::kColumnId && \
68
0
                 operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kValue) {    \
69
0
        col_expr = &operands.Get(1);                                                    \
70
0
        val_expr = &operands.Get(0);                                                    \
71
46
      } else {                                                                          \
72
46
        return;                                                                         \
73
46
      }
74
75
    // For relational conditions, the ranges are as follows. If the column is not a range column,
76
    // just return since it doesn't impose a bound on a range column.
77
    //
78
    // We are not distinguishing between < and <= currently but treat the bound as inclusive lower
79
    // bound. After all, the bound is just a superset of the scan range and as a best-effort
80
    // measure. There may be a some ways to optimize and distinguish the two in future, like using
81
    // exclusive lower bound in DocRowwiseIterator or increment the bound value by "1" to become
82
    // inclusive bound. Same for > and >=.
83
31.2k
    case QL_OP_EQUAL: {
84
31.2k
      if (has_range_column) {
85
        // - <column> = <value> --> min/max values = <value>
86
30.3k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
87
30.3k
        const ColumnId column_id(col_expr->column_id());
88
30.3k
        ranges_.at(column_id).min_value = val_expr->value();
89
30.3k
        ranges_.at(column_id).max_value = val_expr->value();
90
30.3k
      }
91
31.2k
      return;
92
31.2k
    }
93
5.07k
    case QL_OP_LESS_THAN:
94
5.27k
    case QL_OP_LESS_THAN_EQUAL: {
95
5.27k
      if (has_range_column) {
96
4.95k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
97
4.95k
        const ColumnId column_id(col_expr->column_id());
98
4.95k
        if (operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kColumnId) {
99
          // - <column> <= <value> --> max_value = <value>
100
4.95k
          ranges_.at(column_id).max_value = val_expr->value();
101
0
        } else {
102
          // - <value> <= <column> --> min_value = <value>
103
0
          ranges_.at(column_id).min_value = val_expr->value();
104
0
        }
105
4.95k
      }
106
5.27k
      return;
107
5.27k
    }
108
5.12k
    case QL_OP_GREATER_THAN:
109
5.43k
    case QL_OP_GREATER_THAN_EQUAL: {
110
5.43k
      if (has_range_column) {
111
5.01k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
112
4.98k
        const ColumnId column_id(col_expr->column_id());
113
4.98k
        if (operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kColumnId) {
114
          // - <column> >= <value> --> min_value = <value>
115
4.98k
          ranges_.at(column_id).min_value = val_expr->value();
116
18.4E
        } else {
117
          // - <value> >= <column> --> max_value = <value>
118
18.4E
          ranges_.at(column_id).max_value = val_expr->value();
119
18.4E
        }
120
4.98k
      }
121
5.40k
      return;
122
5.43k
    }
123
0
    case QL_OP_BETWEEN: {
124
0
      if (has_range_column) {
125
        // <column> BETWEEN <value_1> <value_2>:
126
        // - min_value = <value_1>
127
        // - max_value = <value_2>
128
0
        CHECK_EQ(operands.size(), 3);
129
0
        if (operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kColumnId) {
130
0
          const ColumnId column_id(operands.Get(0).column_id());
131
0
          if (operands.Get(1).expr_case() == QLExpressionPB::ExprCase::kValue) {
132
0
            ranges_.at(column_id).min_value = operands.Get(1).value();
133
0
          }
134
0
          if (operands.Get(2).expr_case() == QLExpressionPB::ExprCase::kValue) {
135
0
            ranges_.at(column_id).max_value = operands.Get(2).value();
136
0
          }
137
0
        }
138
0
      }
139
0
      return;
140
5.43k
    }
141
796
    case QL_OP_IN: {
142
796
      if (has_range_column) {
143
649
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
144
        // - <column> IN (<value>) --> min/max values = <value>
145
        // IN arguments should have already been de-duplicated and ordered by the executor.
146
640
        int in_size = val_expr->value().list_value().elems_size();
147
640
        if (in_size > 0) {
148
634
          const ColumnId column_id(col_expr->column_id());
149
634
          ranges_.at(column_id).min_value = val_expr->value().list_value().elems(0);
150
634
          ranges_.at(column_id).max_value = val_expr->value().list_value().elems(in_size - 1);
151
634
        }
152
640
        has_in_range_options_ = true;
153
640
      }
154
787
      return;
155
796
    }
156
157
796
#undef QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN
158
159
      // For logical conditions, the ranges are union/intersect/complement of the operands' ranges.
160
36.6k
    case QL_OP_AND: {
161
36.6k
      CHECK_GT(operands.size(), 0);
162
43.0k
      for (const auto& operand : operands) {
163
43.0k
        CHECK_EQ(operand.expr_case(), QLExpressionPB::ExprCase::kCondition);
164
43.0k
        *this &= QLScanRange(schema_, operand.condition());
165
43.0k
      }
166
36.6k
      return;
167
796
    }
168
0
    case QL_OP_OR: {
169
0
      CHECK_GT(operands.size(), 0);
170
0
      for (const auto& operand : operands) {
171
0
        CHECK_EQ(operand.expr_case(), QLExpressionPB::ExprCase::kCondition);
172
0
        *this |= QLScanRange(schema_, operand.condition());
173
0
      }
174
0
      return;
175
796
    }
176
0
    case QL_OP_NOT: {
177
0
      CHECK_EQ(operands.size(), 1);
178
0
      CHECK_EQ(operands.Get(0).expr_case(), QLExpressionPB::ExprCase::kCondition);
179
0
      *this = std::move(~QLScanRange(schema_, operands.Get(0).condition()));
180
0
      return;
181
796
    }
182
183
0
    case QL_OP_IS_NULL:     FALLTHROUGH_INTENDED;
184
0
    case QL_OP_IS_NOT_NULL: FALLTHROUGH_INTENDED;
185
0
    case QL_OP_IS_TRUE:     FALLTHROUGH_INTENDED;
186
0
    case QL_OP_IS_FALSE:    FALLTHROUGH_INTENDED;
187
198
    case QL_OP_NOT_EQUAL:   FALLTHROUGH_INTENDED;
188
198
    case QL_OP_LIKE:        FALLTHROUGH_INTENDED;
189
198
    case QL_OP_NOT_LIKE:    FALLTHROUGH_INTENDED;
190
252
    case QL_OP_NOT_IN:      FALLTHROUGH_INTENDED;
191
252
    case QL_OP_NOT_BETWEEN:
192
      // No simple range can be deduced from these conditions. So the range will be unbounded.
193
252
      return;
194
195
0
    case QL_OP_EXISTS:     FALLTHROUGH_INTENDED;
196
0
    case QL_OP_NOT_EXISTS: FALLTHROUGH_INTENDED;
197
0
    case QL_OP_NOOP:
198
0
      break;
199
200
      // default: fall through
201
0
  }
202
203
0
  LOG(FATAL) << "Internal error: illegal or unknown operator " << condition.op();
204
0
}
205
206
QLScanRange::QLScanRange(const Schema& schema, const PgsqlConditionPB& condition)
207
11.1k
    : schema_(schema) {
208
209
  // If there is no range column, return.
210
11.1k
  if (schema_.num_range_key_columns() == 0) {
211
0
    return;
212
0
  }
213
214
  // Initialize the lower/upper bounds of each range column to null to mean it is unbounded.
215
11.1k
  ranges_.reserve(schema_.num_range_key_columns());
216
37.4k
  for (size_t i = 0; i < schema.num_key_columns(); i++) {
217
26.3k
    if (schema.is_range_column(i)) {
218
21.8k
      ranges_.emplace(schema.column_id(i), QLRange());
219
21.8k
    }
220
26.3k
  }
221
222
  // Check if there is a range column referenced in the operands.
223
11.1k
  const auto& operands = condition.operands();
224
11.1k
  bool has_range_column = false;
225
11.1k
  for (const auto& operand : operands) {
226
11.1k
    if (operand.expr_case() == PgsqlExpressionPB::ExprCase::kColumnId &&
227
6.31k
        schema.is_range_column(ColumnId(operand.column_id()))) {
228
6.31k
      has_range_column = true;
229
6.31k
      break;
230
6.31k
    }
231
11.1k
  }
232
233
11.1k
  switch (condition.op()) {
234
235
0
#define QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr)                       \
236
6.19k
      CHECK_EQ(operands.size(), 2);                                                     \
237
6.19k
      PgsqlExpressionPB const* col_expr = nullptr;                                        \
238
6.19k
      PgsqlExpressionPB const* val_expr = nullptr;                                        \
239
6.19k
      if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId &&        \
240
6.19k
          operands.Get(1).expr_case() == PgsqlExpressionPB::ExprCase::kValue) {           \
241
6.19k
        col_expr = &operands.Get(0);                                                    \
242
6.19k
        val_expr = &operands.Get(1);                                                    \
243
0
      } else if (operands.Get(1).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId && \
244
0
                 operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kValue) {    \
245
0
        col_expr = &operands.Get(1);                                                    \
246
0
        val_expr = &operands.Get(0);                                                    \
247
0
      } else {                                                                          \
248
0
        return;                                                                         \
249
0
      }
250
251
    // For relational conditions, the ranges are as follows. If the column is not a range column,
252
    // just return since it doesn't impose a bound on a range column.
253
    //
254
    // We are not distinguishing between < and <= currently but treat the bound as inclusive lower
255
    // bound. After all, the bound is just a superset of the scan range and as a best-effort
256
    // measure. There may be a some ways to optimize and distinguish the two in future, like using
257
    // exclusive lower bound in DocRowwiseIterator or increment the bound value by "1" to become
258
    // inclusive bound. Same for > and >=.
259
5.47k
    case QL_OP_EQUAL: {
260
5.47k
      if (has_range_column) {
261
        // - <column> = <value> --> min/max values = <value>
262
5.47k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
263
5.47k
        const ColumnId column_id(col_expr->column_id());
264
5.47k
        ranges_.at(column_id).min_value = val_expr->value();
265
5.47k
        ranges_.at(column_id).max_value = val_expr->value();
266
5.47k
      }
267
5.47k
      return;
268
5.47k
    }
269
0
    case QL_OP_LESS_THAN:
270
45
    case QL_OP_LESS_THAN_EQUAL: {
271
45
      if (has_range_column) {
272
45
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
273
45
        const ColumnId column_id(col_expr->column_id());
274
45
        if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId) {
275
          // - <column> <= <value> --> max_value = <value>
276
45
          ranges_.at(column_id).max_value = val_expr->value();
277
0
        } else {
278
          // - <value> <= <column> --> min_value = <value>
279
0
          ranges_.at(column_id).min_value = val_expr->value();
280
0
        }
281
45
      }
282
45
      return;
283
45
    }
284
0
    case QL_OP_GREATER_THAN:
285
43
    case QL_OP_GREATER_THAN_EQUAL: {
286
43
      if (has_range_column) {
287
43
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
288
43
        const ColumnId column_id (col_expr->column_id());
289
43
        if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId) {
290
          // - <column> >= <value> --> min_value = <value>
291
43
          ranges_.at(column_id).min_value = val_expr->value();
292
0
        } else {
293
          // - <value> >= <column> --> max_value = <value>
294
0
          ranges_.at(column_id).max_value = val_expr->value();
295
0
        }
296
43
      }
297
43
      return;
298
43
    }
299
115
    case QL_OP_BETWEEN: {
300
115
      if (has_range_column) {
301
        // <column> BETWEEN <value_1> <value_2>:
302
        // - min_value = <value_1>
303
        // - max_value = <value_2>
304
115
        CHECK_EQ(operands.size(), 3);
305
115
        if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId) {
306
115
          const ColumnId column_id(operands.Get(0).column_id());
307
115
          if (operands.Get(1).expr_case() == PgsqlExpressionPB::ExprCase::kValue) {
308
115
            ranges_.at(column_id).min_value = operands.Get(1).value();
309
115
          }
310
115
          if (operands.Get(2).expr_case() == PgsqlExpressionPB::ExprCase::kValue) {
311
115
            ranges_.at(column_id).max_value = operands.Get(2).value();
312
115
          }
313
115
        }
314
115
      }
315
115
      return;
316
43
    }
317
632
    case QL_OP_IN: {
318
632
      if (has_range_column) {
319
632
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
320
        // - <column> IN (<value>) --> min/max values = <value>
321
        // IN arguments should have already been de-duplicated and ordered by the executor.
322
632
        int in_size = val_expr->value().list_value().elems_size();
323
632
        if (in_size > 0) {
324
632
          const ColumnId column_id(col_expr->column_id());
325
632
          ranges_.at(column_id).min_value = val_expr->value().list_value().elems(0);
326
632
          ranges_.at(column_id).max_value = val_expr->value().list_value().elems(in_size - 1);
327
632
        }
328
632
        has_in_range_options_ = true;
329
632
      }
330
632
      return;
331
632
    }
332
333
632
#undef QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN
334
335
      // For logical conditions, the ranges are union/intersect/complement of the operands' ranges.
336
4.81k
    case QL_OP_AND: {
337
4.81k
      CHECK_GT(operands.size(), 0);
338
4.87k
      for (const auto& operand : operands) {
339
4.87k
        CHECK_EQ(operand.expr_case(), PgsqlExpressionPB::ExprCase::kCondition);
340
4.87k
        *this &= QLScanRange(schema_, operand.condition());
341
4.87k
      }
342
4.81k
      return;
343
632
    }
344
0
    case QL_OP_OR: {
345
0
      CHECK_GT(operands.size(), 0);
346
0
      for (const auto& operand : operands) {
347
0
        CHECK_EQ(operand.expr_case(), PgsqlExpressionPB::ExprCase::kCondition);
348
0
        *this |= QLScanRange(schema_, operand.condition());
349
0
      }
350
0
      return;
351
632
    }
352
0
    case QL_OP_NOT: {
353
0
      CHECK_EQ(operands.size(), 1);
354
0
      CHECK_EQ(operands.Get(0).expr_case(), PgsqlExpressionPB::ExprCase::kCondition);
355
0
      *this = std::move(~QLScanRange(schema_, operands.Get(0).condition()));
356
0
      return;
357
632
    }
358
359
0
    case QL_OP_IS_NULL:     FALLTHROUGH_INTENDED;
360
0
    case QL_OP_IS_NOT_NULL: FALLTHROUGH_INTENDED;
361
0
    case QL_OP_IS_TRUE:     FALLTHROUGH_INTENDED;
362
0
    case QL_OP_IS_FALSE:    FALLTHROUGH_INTENDED;
363
0
    case QL_OP_NOT_EQUAL:   FALLTHROUGH_INTENDED;
364
0
    case QL_OP_LIKE:        FALLTHROUGH_INTENDED;
365
0
    case QL_OP_NOT_LIKE:    FALLTHROUGH_INTENDED;
366
0
    case QL_OP_NOT_IN:      FALLTHROUGH_INTENDED;
367
0
    case QL_OP_NOT_BETWEEN:
368
      // No simple range can be deduced from these conditions. So the range will be unbounded.
369
0
      return;
370
371
0
    case QL_OP_EXISTS:     FALLTHROUGH_INTENDED;
372
0
    case QL_OP_NOT_EXISTS: FALLTHROUGH_INTENDED;
373
0
    case QL_OP_NOOP:
374
0
      break;
375
376
      // default: fall through
377
0
  }
378
379
0
  LOG(FATAL) << "Internal error: illegal or unknown operator " << condition.op();
380
0
}
381
382
47.9k
QLScanRange& QLScanRange::operator&=(const QLScanRange& other) {
383
87.0k
  for (auto& elem : ranges_) {
384
87.0k
    auto& range = elem.second;
385
87.0k
    const auto& other_range = other.ranges_.at(elem.first);
386
387
    // Intersect operation:
388
    // - min_value = max(min_value, other_min_value)
389
    // - max_value = min(max_value, other_max_value)
390
87.0k
    if (range.min_value && other_range.min_value) {
391
0
      range.min_value = std::max(range.min_value, other_range.min_value);
392
87.0k
    } else if (other_range.min_value) {
393
40.7k
      range.min_value = other_range.min_value;
394
40.7k
    }
395
396
87.0k
    if (range.max_value && other_range.max_value) {
397
0
      range.max_value = std::min(range.max_value, other_range.max_value);
398
87.0k
    } else if (other_range.max_value) {
399
40.7k
      range.max_value = other_range.max_value;
400
40.7k
    }
401
87.0k
  }
402
47.9k
  has_in_range_options_ = has_in_range_options_ || other.has_in_range_options_;
403
404
47.9k
  return *this;
405
47.9k
}
406
407
0
QLScanRange& QLScanRange::operator|=(const QLScanRange& other) {
408
0
  for (auto& elem : ranges_) {
409
0
    auto& range = elem.second;
410
0
    const auto& other_range = other.ranges_.at(elem.first);
411
412
    // Union operation:
413
    // - min_value = min(min_value, other_min_value)
414
    // - max_value = max(max_value, other_max_value)
415
0
    if (range.min_value && other_range.min_value) {
416
0
      range.min_value = std::min(range.min_value, other_range.min_value);
417
0
    } else if (!other_range.min_value) {
418
0
      range.min_value = boost::none;
419
0
    }
420
421
0
    if (range.max_value && other_range.max_value) {
422
0
      range.max_value = std::max(range.max_value, other_range.max_value);
423
0
    } else if (!other_range.max_value) {
424
0
      range.max_value = boost::none;
425
0
    }
426
0
  }
427
0
  has_in_range_options_ = has_in_range_options_ && other.has_in_range_options_;
428
429
0
  return *this;
430
0
}
431
432
0
QLScanRange& QLScanRange::operator~() {
433
0
  for (auto& elem : ranges_) {
434
0
    auto& range = elem.second;
435
436
    // Complement operation:
437
0
    if (range.min_value && range.max_value) {
438
      // If the condition's min and max values are defined, the negation of it will be
439
      // disjoint ranges at the two ends, which is not representable as a simple range. So
440
      // we will treat the result as unbounded.
441
0
      range.min_value = boost::none;
442
0
      range.max_value = boost::none;
443
0
    } else {
444
      // Otherwise, for one-sided range or unbounded range, the resulting min/max values are
445
      // just the reverse of the bounds.
446
447
0
      range.min_value.swap(range.max_value);
448
0
    }
449
0
  }
450
0
  has_in_range_options_ = false;
451
452
0
  return *this;
453
0
}
454
455
0
QLScanRange& QLScanRange::operator=(QLScanRange&& other) {
456
0
  ranges_ = std::move(other.ranges_);
457
0
  return *this;
458
0
}
459
460
//-------------------------------------- QL scan spec ---------------------------------------
461
462
QLScanSpec::QLScanSpec(QLExprExecutorPtr executor)
463
0
    : QLScanSpec(nullptr, nullptr, true, std::move(executor)) {
464
0
}
Unexecuted instantiation: _ZN2yb10QLScanSpecC2ENSt3__110shared_ptrINS_14QLExprExecutorEEE
Unexecuted instantiation: _ZN2yb10QLScanSpecC1ENSt3__110shared_ptrINS_14QLExprExecutorEEE
465
466
QLScanSpec::QLScanSpec(const QLConditionPB* condition,
467
                       const QLConditionPB* if_condition,
468
                       const bool is_forward_scan,
469
                       QLExprExecutorPtr executor)
470
    : YQLScanSpec(YQL_CLIENT_CQL),
471
      condition_(condition),
472
      if_condition_(if_condition),
473
      is_forward_scan_(is_forward_scan),
474
3.98M
      executor_(std::move(executor)) {
475
3.98M
  if (executor_ == nullptr) {
476
258k
    executor_ = std::make_shared<QLExprExecutor>();
477
258k
  }
478
3.98M
}
479
480
// Evaluate the WHERE condition for the given row.
481
7.60M
CHECKED_STATUS QLScanSpec::Match(const QLTableRow& table_row, bool* match) const {
482
7.60M
  bool cond = true;
483
7.60M
  bool if_cond = true;
484
7.60M
  if (condition_ != nullptr) {
485
657k
    RETURN_NOT_OK(executor_->EvalCondition(*condition_, table_row, &cond));
486
657k
  }
487
7.60M
  if (if_condition_ != nullptr) {
488
562
    RETURN_NOT_OK(executor_->EvalCondition(*if_condition_, table_row, &if_cond));
489
562
  }
490
7.60M
  *match = cond && if_cond;
491
7.60M
  return Status::OK();
492
7.60M
}
493
494
//-------------------------------------- QL scan spec ---------------------------------------
495
// Pgsql scan specification.
496
PgsqlScanSpec::PgsqlScanSpec(const PgsqlExpressionPB *where_expr,
497
                             QLExprExecutor::SharedPtr executor)
498
    : YQLScanSpec(YQL_CLIENT_PGSQL),
499
      where_expr_(where_expr),
500
4.32M
      executor_(executor) {
501
4.32M
  if (executor_ == nullptr) {
502
4.32M
    executor_ = std::make_shared<QLExprExecutor>();
503
4.32M
  }
504
4.32M
}
505
506
4.33M
PgsqlScanSpec::~PgsqlScanSpec() {
507
4.33M
}
508
509
} // namespace yb