YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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
122k
    : schema_(schema) {
32
33
  // If there is no range column, return.
34
122k
  if (schema_.num_range_key_columns() == 0) {
35
2.05k
    return;
36
2.05k
  }
37
38
  // Initialize the lower/upper bounds of each range column to null to mean it is unbounded.
39
120k
  ranges_.reserve(schema_.num_range_key_columns());
40
382k
  for (size_t i = 0; i < schema.num_key_columns(); 
i++262k
) {
41
262k
    if (schema.is_range_column(i)) {
42
216k
      ranges_.emplace(schema.column_id(i), QLRange());
43
216k
    }
44
262k
  }
45
46
  // Check if there is a range column referenced in the operands.
47
120k
  const auto& operands = condition.operands();
48
120k
  bool has_range_column = false;
49
129k
  for (const auto& operand : operands) {
50
129k
    if (operand.expr_case() == QLExpressionPB::ExprCase::kColumnId &&
51
129k
        
schema.is_range_column(ColumnId(operand.column_id()))66.5k
) {
52
63.7k
      has_range_column = true;
53
63.7k
      break;
54
63.7k
    }
55
129k
  }
56
57
120k
  switch (condition.op()) {
58
59
0
#define QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr)                       \
60
63.7k
      CHECK_EQ(operands.size(), 2);                                                     \
61
63.7k
      QLExpressionPB const* col_expr = nullptr;                                        \
62
63.7k
      QLExpressionPB const* val_expr = nullptr;                                        \
63
63.7k
      if (operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kColumnId &&        \
64
63.7k
          
operands.Get(1).expr_case() == QLExpressionPB::ExprCase::kValue63.6k
) { \
65
63.6k
        col_expr = &operands.Get(0);                                                    \
66
63.6k
        val_expr = &operands.Get(1);                                                    \
67
63.6k
      } else 
if (52
operands.Get(1).expr_case() == QLExpressionPB::ExprCase::kColumnId52
&& \
68
52
                 
operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kValue0
) { \
69
0
        col_expr = &operands.Get(1);                                                    \
70
0
        val_expr = &operands.Get(0);                                                    \
71
52
      } else {                                                                          \
72
52
        return;                                                                         \
73
52
      }
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
48.7k
    case QL_OP_EQUAL: {
84
48.7k
      if (has_range_column) {
85
        // - <column> = <value> --> min/max values = <value>
86
46.9k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
87
46.9k
        const ColumnId column_id(col_expr->column_id());
88
46.9k
        ranges_.at(column_id).min_value = val_expr->value();
89
46.9k
        ranges_.at(column_id).max_value = val_expr->value();
90
46.9k
      }
91
48.7k
      return;
92
48.7k
    }
93
48.7k
    case QL_OP_LESS_THAN:
94
8.36k
    case QL_OP_LESS_THAN_EQUAL: {
95
8.36k
      if (has_range_column) {
96
8.06k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
97
8.05k
        const ColumnId column_id(col_expr->column_id());
98
8.05k
        if (operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kColumnId) {
99
          // - <column> <= <value> --> max_value = <value>
100
8.05k
          ranges_.at(column_id).max_value = val_expr->value();
101
8.05k
        } else {
102
          // - <value> <= <column> --> min_value = <value>
103
4
          ranges_.at(column_id).min_value = val_expr->value();
104
4
        }
105
8.05k
      }
106
8.35k
      return;
107
8.36k
    }
108
8.35k
    case QL_OP_GREATER_THAN:
109
8.53k
    case QL_OP_GREATER_THAN_EQUAL: {
110
8.53k
      if (has_range_column) {
111
8.12k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
112
8.09k
        const ColumnId column_id(col_expr->column_id());
113
8.09k
        if (operands.Get(0).expr_case() == QLExpressionPB::ExprCase::kColumnId) {
114
          // - <column> >= <value> --> min_value = <value>
115
8.09k
          ranges_.at(column_id).min_value = val_expr->value();
116
8.09k
        } else {
117
          // - <value> >= <column> --> max_value = <value>
118
0
          ranges_.at(column_id).max_value = val_expr->value();
119
0
        }
120
8.09k
      }
121
8.50k
      return;
122
8.53k
    }
123
8.50k
    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
8.53k
    }
141
787
    case QL_OP_IN: {
142
787
      if (has_range_column) {
143
641
        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
633
        int in_size = val_expr->value().list_value().elems_size();
147
642
        if (
in_size > 0633
) {
148
642
          const ColumnId column_id(col_expr->column_id());
149
642
          ranges_.at(column_id).min_value = val_expr->value().list_value().elems(0);
150
642
          ranges_.at(column_id).max_value = val_expr->value().list_value().elems(in_size - 1);
151
642
        }
152
633
        has_in_range_options_ = true;
153
633
      }
154
779
      return;
155
787
    }
156
157
779
#undef QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN
158
159
      // For logical conditions, the ranges are union/intersect/complement of the operands' ranges.
160
53.3k
    case QL_OP_AND: {
161
53.3k
      CHECK_GT(operands.size(), 0);
162
59.9k
      for (const auto& operand : operands) {
163
59.9k
        CHECK_EQ(operand.expr_case(), QLExpressionPB::ExprCase::kCondition);
164
59.9k
        *this &= QLScanRange(schema_, operand.condition());
165
59.9k
      }
166
53.3k
      return;
167
787
    }
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
787
    }
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
787
    }
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
120k
  }
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
30.8k
    : schema_(schema) {
208
209
  // If there is no range column, return.
210
30.8k
  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
30.8k
  ranges_.reserve(schema_.num_range_key_columns());
216
93.6k
  for (size_t i = 0; i < schema.num_key_columns(); 
i++62.7k
) {
217
62.7k
    if (schema.is_range_column(i)) {
218
58.0k
      ranges_.emplace(schema.column_id(i), QLRange());
219
58.0k
    }
220
62.7k
  }
221
222
  // Check if there is a range column referenced in the operands.
223
30.8k
  const auto& operands = condition.operands();
224
30.8k
  bool has_range_column = false;
225
31.1k
  for (const auto& operand : operands) {
226
31.1k
    if (operand.expr_case() == PgsqlExpressionPB::ExprCase::kColumnId &&
227
31.1k
        
schema.is_range_column(ColumnId(operand.column_id()))18.5k
) {
228
18.5k
      has_range_column = true;
229
18.5k
      break;
230
18.5k
    }
231
31.1k
  }
232
233
30.8k
  switch (condition.op()) {
234
235
0
#define QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr)                       \
236
18.2k
      CHECK_EQ(operands.size(), 2);                                                     \
237
18.2k
      PgsqlExpressionPB const* col_expr = nullptr;                                        \
238
18.2k
      PgsqlExpressionPB const* val_expr = nullptr;                                        \
239
18.2k
      if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId &&        \
240
18.2k
          operands.Get(1).expr_case() == PgsqlExpressionPB::ExprCase::kValue) {           \
241
18.2k
        col_expr = &operands.Get(0);                                                    \
242
18.2k
        val_expr = &operands.Get(1);                                                    \
243
18.2k
      } else 
if (1
operands.Get(1).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId1
&& \
244
1
                 
operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kValue0
) { \
245
0
        col_expr = &operands.Get(1);                                                    \
246
0
        val_expr = &operands.Get(0);                                                    \
247
1
      } else {                                                                          \
248
1
        return;                                                                         \
249
1
      }
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
15.8k
    case QL_OP_EQUAL: {
260
15.8k
      if (
has_range_column15.8k
) {
261
        // - <column> = <value> --> min/max values = <value>
262
15.8k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
263
15.8k
        const ColumnId column_id(col_expr->column_id());
264
15.8k
        ranges_.at(column_id).min_value = val_expr->value();
265
15.8k
        ranges_.at(column_id).max_value = val_expr->value();
266
15.8k
      }
267
15.8k
      return;
268
15.8k
    }
269
15.8k
    case QL_OP_LESS_THAN:
270
122
    case QL_OP_LESS_THAN_EQUAL: {
271
122
      if (has_range_column) {
272
122
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
273
122
        const ColumnId column_id(col_expr->column_id());
274
122
        if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId) {
275
          // - <column> <= <value> --> max_value = <value>
276
122
          ranges_.at(column_id).max_value = val_expr->value();
277
122
        } else {
278
          // - <value> <= <column> --> min_value = <value>
279
0
          ranges_.at(column_id).min_value = val_expr->value();
280
0
        }
281
122
      }
282
122
      return;
283
122
    }
284
122
    case QL_OP_GREATER_THAN:
285
1.55k
    case QL_OP_GREATER_THAN_EQUAL: {
286
1.55k
      if (has_range_column) {
287
1.55k
        QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN(col_expr, val_expr);
288
1.55k
        const ColumnId column_id (col_expr->column_id());
289
1.55k
        if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId) {
290
          // - <column> >= <value> --> min_value = <value>
291
1.55k
          ranges_.at(column_id).min_value = val_expr->value();
292
1.55k
        } else {
293
          // - <value> >= <column> --> max_value = <value>
294
0
          ranges_.at(column_id).max_value = val_expr->value();
295
0
        }
296
1.55k
      }
297
1.55k
      return;
298
1.55k
    }
299
1.55k
    case QL_OP_BETWEEN: {
300
284
      if (has_range_column) {
301
        // <column> BETWEEN <value_1> <value_2>:
302
        // - min_value = <value_1>
303
        // - max_value = <value_2>
304
284
        CHECK_EQ(operands.size(), 3);
305
284
        if (operands.Get(0).expr_case() == PgsqlExpressionPB::ExprCase::kColumnId) {
306
284
          const ColumnId column_id(operands.Get(0).column_id());
307
284
          if (operands.Get(1).expr_case() == PgsqlExpressionPB::ExprCase::kValue) {
308
284
            ranges_.at(column_id).min_value = operands.Get(1).value();
309
284
          }
310
284
          if (operands.Get(2).expr_case() == PgsqlExpressionPB::ExprCase::kValue) {
311
284
            ranges_.at(column_id).max_value = operands.Get(2).value();
312
284
          }
313
284
        }
314
284
      }
315
284
      return;
316
1.55k
    }
317
743
    case QL_OP_IN: {
318
743
      if (has_range_column) {
319
743
        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
743
        int in_size = val_expr->value().list_value().elems_size();
323
743
        if (in_size > 0) {
324
743
          const ColumnId column_id(col_expr->column_id());
325
743
          ranges_.at(column_id).min_value = val_expr->value().list_value().elems(0);
326
743
          ranges_.at(column_id).max_value = val_expr->value().list_value().elems(in_size - 1);
327
743
        }
328
743
        has_in_range_options_ = true;
329
743
      }
330
743
      return;
331
743
    }
332
333
743
#undef QL_GET_COLUMN_VALUE_EXPR_ELSE_RETURN
334
335
      // For logical conditions, the ranges are union/intersect/complement of the operands' ranges.
336
12.3k
    case QL_OP_AND: {
337
12.3k
      CHECK_GT(operands.size(), 0);
338
12.6k
      for (const auto& operand : operands) {
339
12.6k
        CHECK_EQ(operand.expr_case(), PgsqlExpressionPB::ExprCase::kCondition);
340
12.6k
        *this &= QLScanRange(schema_, operand.condition());
341
12.6k
      }
342
12.3k
      return;
343
743
    }
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
743
    }
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
743
    }
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
30.8k
  }
378
379
0
  LOG(FATAL) << "Internal error: illegal or unknown operator " << condition.op();
380
0
}
381
382
72.5k
QLScanRange& QLScanRange::operator&=(const QLScanRange& other) {
383
135k
  for (auto& elem : ranges_) {
384
135k
    auto& range = elem.second;
385
135k
    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
135k
    if (range.min_value && 
other_range.min_value6.10k
) {
391
0
      range.min_value = std::max(range.min_value, other_range.min_value);
392
135k
    } else if (other_range.min_value) {
393
64.2k
      range.min_value = other_range.min_value;
394
64.2k
    }
395
396
135k
    if (range.max_value && 
other_range.max_value1.18k
) {
397
0
      range.max_value = std::min(range.max_value, other_range.max_value);
398
135k
    } else if (other_range.max_value) {
399
63.8k
      range.max_value = other_range.max_value;
400
63.8k
    }
401
135k
  }
402
72.5k
  has_in_range_options_ = has_in_range_options_ || 
other.has_in_range_options_72.4k
;
403
404
72.5k
  return *this;
405
72.5k
}
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: yb::QLScanSpec::QLScanSpec(std::__1::shared_ptr<yb::QLExprExecutor>)
Unexecuted instantiation: yb::QLScanSpec::QLScanSpec(std::__1::shared_ptr<yb::QLExprExecutor>)
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
7.61M
      executor_(std::move(executor)) {
475
7.61M
  if (executor_ == nullptr) {
476
259k
    executor_ = std::make_shared<QLExprExecutor>();
477
259k
  }
478
7.61M
}
479
480
// Evaluate the WHERE condition for the given row.
481
11.0M
CHECKED_STATUS QLScanSpec::Match(const QLTableRow& table_row, bool* match) const {
482
11.0M
  bool cond = true;
483
11.0M
  bool if_cond = true;
484
11.0M
  if (condition_ != nullptr) {
485
661k
    RETURN_NOT_OK(executor_->EvalCondition(*condition_, table_row, &cond));
486
661k
  }
487
11.0M
  if (if_condition_ != nullptr) {
488
642
    RETURN_NOT_OK(executor_->EvalCondition(*if_condition_, table_row, &if_cond));
489
642
  }
490
11.0M
  *match = cond && 
if_cond10.9M
;
491
11.0M
  return Status::OK();
492
11.0M
}
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
11.6M
      executor_(executor) {
501
11.6M
  if (
executor_ == nullptr11.6M
) {
502
11.6M
    executor_ = std::make_shared<QLExprExecutor>();
503
11.6M
  }
504
11.6M
}
505
506
11.6M
PgsqlScanSpec::~PgsqlScanSpec() {
507
11.6M
}
508
509
} // namespace yb