/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 |