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