/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/ptree/pt_expr.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //-------------------------------------------------------------------------------------------------- |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
5 | | // in compliance with the License. You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
10 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
11 | | // or implied. See the License for the specific language governing permissions and limitations |
12 | | // under the License. |
13 | | // |
14 | | // |
15 | | // Treenode definitions for expressions. |
16 | | //-------------------------------------------------------------------------------------------------- |
17 | | |
18 | | #include "yb/yql/cql/ql/ptree/pt_expr.h" |
19 | | |
20 | | #include "yb/bfql/tserver_opcodes.h" |
21 | | |
22 | | #include "yb/client/table.h" |
23 | | |
24 | | #include "yb/common/common.pb.h" |
25 | | #include "yb/common/index.h" |
26 | | #include "yb/common/index_column.h" |
27 | | #include "yb/common/ql_type.h" |
28 | | |
29 | | #include "yb/gutil/casts.h" |
30 | | |
31 | | #include "yb/util/date_time.h" |
32 | | #include "yb/util/decimal.h" |
33 | | #include "yb/util/net/inetaddress.h" |
34 | | #include "yb/util/net/net_util.h" |
35 | | #include "yb/util/stol_utils.h" |
36 | | |
37 | | #include "yb/yql/cql/ql/ptree/column_desc.h" |
38 | | #include "yb/yql/cql/ql/ptree/pt_bcall.h" |
39 | | #include "yb/yql/cql/ql/ptree/pt_select.h" |
40 | | #include "yb/yql/cql/ql/ptree/pt_type.h" |
41 | | #include "yb/yql/cql/ql/ptree/sem_context.h" |
42 | | #include "yb/yql/cql/ql/ptree/yb_location.h" |
43 | | |
44 | | namespace yb { |
45 | | namespace ql { |
46 | | |
47 | | using client::YBColumnSchema; |
48 | | using std::shared_ptr; |
49 | | |
50 | | //-------------------------------------------------------------------------------------------------- |
51 | | |
52 | | PTExpr::PTExpr( |
53 | | MemoryContext *memctx, |
54 | | YBLocation::SharedPtr loc, |
55 | | ExprOperator op, |
56 | | yb::QLOperator ql_op, |
57 | | InternalType internal_type, |
58 | | DataType ql_type_id) |
59 | 1.16M | : PTExpr(memctx, loc, op, ql_op, internal_type, QLType::Create(ql_type_id)) { |
60 | 1.16M | } |
61 | | |
62 | | PTExpr::PTExpr( |
63 | | MemoryContext *memctx, |
64 | | YBLocation::SharedPtr loc, |
65 | | ExprOperator op, |
66 | | yb::QLOperator ql_op, |
67 | | InternalType internal_type, |
68 | | const QLTypePtr& ql_type) |
69 | | : TreeNode(memctx, loc), |
70 | | op_(op), |
71 | | ql_op_(ql_op), |
72 | | internal_type_(internal_type), |
73 | | ql_type_(ql_type), |
74 | | expected_internal_type_(InternalType::VALUE_NOT_SET), |
75 | | is_in_operand_(false), |
76 | 1.17M | index_name_(MCMakeShared<MCString>(memctx)) { |
77 | 1.17M | } |
78 | | |
79 | 0 | void PTExpr::set_ql_type(DataType type_id) { |
80 | 0 | ql_type_ = QLType::Create(type_id); |
81 | 0 | } |
82 | | |
83 | 979 | void PTExpr::set_ql_type_id(DataType type_id) { |
84 | 979 | ql_type_ = QLType::Create(type_id); |
85 | 979 | } |
86 | | |
87 | 5.05M | DataType PTExpr::ql_type_id() const { |
88 | 5.05M | return ql_type_->main(); |
89 | 5.05M | } |
90 | | |
91 | 1.48M | bool PTExpr::has_valid_ql_type_id() { |
92 | 1.48M | return ql_type_->main() != DataType::UNKNOWN_DATA; |
93 | 1.48M | } |
94 | | |
95 | 0 | bfql::TSOpcode PTExpr::aggregate_opcode() const { |
96 | 0 | return bfql::TSOpcode::kNoOp; |
97 | 0 | } |
98 | | |
99 | 143k | bool PTExpr::is_null() const { |
100 | 143k | return ql_type_->main() == DataType::NULL_VALUE_TYPE; |
101 | 143k | } |
102 | | |
103 | 319 | std::string PTExpr::MetadataName() const { |
104 | | // If this expression was used to define an index column, use its descriptor name. |
105 | 316 | return index_desc_ ? index_desc_->MetadataName() : QLName(QLNameOption::kMetadataName); |
106 | 319 | } |
107 | | |
108 | 1.48M | bool PTExpr::has_valid_internal_type() { |
109 | | // internal_type_ is not set in case of PTNull. |
110 | 1.48M | return ql_type_->main() == DataType::NULL_VALUE_TYPE || |
111 | 1.32M | internal_type_ != InternalType::VALUE_NOT_SET; |
112 | 1.48M | } |
113 | | |
114 | 392k | void PTExpr::rscol_type_PB(QLTypePB *pb_type ) const { |
115 | 392k | ql_type_->ToQLTypePB(pb_type); |
116 | 392k | } |
117 | | |
118 | 1.50M | bool PTExpr::CheckIndexColumn(SemContext *sem_context) { |
119 | 1.50M | if (!sem_context->selecting_from_index()) { |
120 | 1.49M | return false; |
121 | 1.49M | } |
122 | | |
123 | | // Currently, only PTJsonColumnWithOperators node is allowed to be an IndexColumn. However, define |
124 | | // this analysis in PTExpr class so that it's easier to extend the support INDEX by expression. |
125 | 7.24k | if (op_ != ExprOperator::kJsonOperatorRef) { |
126 | 7.24k | return false; |
127 | 7.24k | } |
128 | | |
129 | | // Check if this expression is used for indexing. |
130 | 18.4E | index_desc_ = GetColumnDesc(sem_context); |
131 | 18.4E | if (index_desc_ != nullptr) { |
132 | | // Type resolution: This expr should have the same datatype as the column. |
133 | 47 | index_name_->assign(QLName().c_str()); |
134 | 47 | internal_type_ = index_desc_->internal_type(); |
135 | 47 | ql_type_ = index_desc_->ql_type(); |
136 | 47 | return true; |
137 | 47 | } |
138 | | |
139 | 18.4E | return false; |
140 | 18.4E | } |
141 | | |
142 | 1.50M | CHECKED_STATUS PTExpr::CheckOperator(SemContext *sem_context) { |
143 | | // Where clause only allow AND, EQ, LT, LE, GT, and GE operators. |
144 | 1.50M | if (sem_context->where_state() != nullptr) { |
145 | 385k | switch (ql_op_) { |
146 | 21.5k | case QL_OP_AND: |
147 | 140k | case QL_OP_EQUAL: |
148 | 140k | case QL_OP_LESS_THAN: |
149 | 141k | case QL_OP_LESS_THAN_EQUAL: |
150 | 141k | case QL_OP_GREATER_THAN: |
151 | 142k | case QL_OP_GREATER_THAN_EQUAL: |
152 | 142k | case QL_OP_IN: |
153 | 142k | case QL_OP_NOT_IN: |
154 | 142k | case QL_OP_NOT_EQUAL: |
155 | 386k | case QL_OP_NOOP: |
156 | 386k | break; |
157 | 0 | default: |
158 | 0 | return sem_context->Error(this, "This operator is not allowed in where clause", |
159 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
160 | 1.50M | } |
161 | 1.50M | } |
162 | | |
163 | | // Partial index where clause only supports these operators: =, AND, !=, >, <, >=, <=. |
164 | 1.50M | if (sem_context->idx_predicate_state() != nullptr) { |
165 | 600 | switch (ql_op_) { |
166 | 48 | case QL_OP_AND: |
167 | 116 | case QL_OP_EQUAL: |
168 | 144 | case QL_OP_NOT_EQUAL: |
169 | 213 | case QL_OP_GREATER_THAN: |
170 | 218 | case QL_OP_GREATER_THAN_EQUAL: |
171 | 223 | case QL_OP_LESS_THAN: |
172 | 228 | case QL_OP_LESS_THAN_EQUAL: |
173 | 600 | case QL_OP_NOOP: |
174 | 600 | break; |
175 | 0 | default: |
176 | 0 | return sem_context->Error(this, |
177 | 0 | "This operator is not allowed in partial index where clause", |
178 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
179 | 1.50M | } |
180 | 1.50M | } |
181 | 1.50M | return Status::OK(); |
182 | 1.50M | } |
183 | | |
184 | 0 | CHECKED_STATUS PTExpr::AnalyzeOperator(SemContext *sem_context) { |
185 | 0 | return Status::OK(); |
186 | 0 | } |
187 | | |
188 | | CHECKED_STATUS PTExpr::AnalyzeOperator(SemContext *sem_context, |
189 | 0 | PTExpr::SharedPtr op1) { |
190 | 0 | return Status::OK(); |
191 | 0 | } |
192 | | |
193 | | CHECKED_STATUS PTExpr::AnalyzeOperator(SemContext *sem_context, |
194 | | PTExpr::SharedPtr op1, |
195 | 0 | PTExpr::SharedPtr op2) { |
196 | 0 | return Status::OK(); |
197 | 0 | } |
198 | | |
199 | | CHECKED_STATUS PTExpr::AnalyzeOperator(SemContext *sem_context, |
200 | | PTExpr::SharedPtr op1, |
201 | | PTExpr::SharedPtr op2, |
202 | 0 | PTExpr::SharedPtr op3) { |
203 | 0 | return Status::OK(); |
204 | 0 | } |
205 | | |
206 | 0 | CHECKED_STATUS PTExpr::SetupSemStateForOp1(SemState *sem_state) { |
207 | 0 | return Status::OK(); |
208 | 0 | } |
209 | | |
210 | 0 | CHECKED_STATUS PTExpr::SetupSemStateForOp2(SemState *sem_state) { |
211 | | // Passing down where clause state variables. |
212 | 0 | return Status::OK(); |
213 | 0 | } |
214 | | |
215 | 0 | CHECKED_STATUS PTExpr::SetupSemStateForOp3(SemState *sem_state) { |
216 | 0 | return Status::OK(); |
217 | 0 | } |
218 | | |
219 | 1.49M | CHECKED_STATUS PTExpr::CheckExpectedTypeCompatibility(SemContext *sem_context) { |
220 | 1.49M | CHECK(has_valid_internal_type() && has_valid_ql_type_id()); |
221 | | |
222 | | // Check if RHS accepts NULL. |
223 | 1.49M | if (ql_type_->main() == DataType::NULL_VALUE_TYPE && |
224 | 158k | !sem_context->expected_ql_type_accepts_null()) { |
225 | 46 | return sem_context->Error(this, ErrorCode::NULL_IN_COLLECTIONS); |
226 | 46 | } |
227 | | |
228 | | // Check if RHS support counter update. |
229 | 1.49M | if (sem_context->processing_set_clause() && |
230 | 7.64k | sem_context->lhs_col() != nullptr && |
231 | 6.49k | sem_context->lhs_col()->is_counter()) { |
232 | 28 | RETURN_NOT_OK(this->CheckCounterUpdateSupport(sem_context)); |
233 | 28 | } |
234 | | |
235 | | // Check if RHS is convertible to LHS. |
236 | 1.49M | if (!sem_context->expr_expected_ql_type()->IsUnknown()) { |
237 | 714k | if (!sem_context->IsConvertible(sem_context->expr_expected_ql_type(), ql_type_)) { |
238 | 142 | return sem_context->Error(this, ErrorCode::DATATYPE_MISMATCH); |
239 | 142 | } |
240 | 1.49M | } |
241 | | |
242 | | // Resolve internal type. |
243 | 1.49M | const InternalType expected_itype = sem_context->expr_expected_internal_type(); |
244 | 1.49M | if (expected_itype == InternalType::VALUE_NOT_SET) { |
245 | 773k | expected_internal_type_ = internal_type_; |
246 | 716k | } else { |
247 | 716k | expected_internal_type_ = expected_itype; |
248 | 716k | } |
249 | 1.49M | return Status::OK(); |
250 | 1.49M | } |
251 | | |
252 | | //-------------------------------------------------------------------------------------------------- |
253 | | CHECKED_STATUS PTExpr::CheckInequalityOperands(SemContext *sem_context, |
254 | | PTExpr::SharedPtr lhs, |
255 | 225k | PTExpr::SharedPtr rhs) { |
256 | 225k | if (!sem_context->IsComparable(lhs->ql_type_id(), rhs->ql_type_id())) { |
257 | 26 | return sem_context->Error(this, "Cannot compare values of these datatypes", |
258 | 26 | ErrorCode::INCOMPARABLE_DATATYPES); |
259 | 26 | } |
260 | 225k | return Status::OK(); |
261 | 225k | } |
262 | | |
263 | | CHECKED_STATUS PTExpr::CheckEqualityOperands(SemContext *sem_context, |
264 | | PTExpr::SharedPtr lhs, |
265 | 222k | PTExpr::SharedPtr rhs) { |
266 | 223k | if (QLType::IsNull(lhs->ql_type_id()) || QLType::IsNull(rhs->ql_type_id())) { |
267 | 799 | return Status::OK(); |
268 | 222k | } else { |
269 | 222k | return CheckInequalityOperands(sem_context, lhs, rhs); |
270 | 222k | } |
271 | 222k | } |
272 | | |
273 | | |
274 | 188 | CHECKED_STATUS PTExpr::CheckLhsExpr(SemContext *sem_context) { |
275 | 188 | if (op_ != ExprOperator::kRef && op_ != ExprOperator::kBcall) { |
276 | 0 | return sem_context->Error(this, |
277 | 0 | "Only column refs and builtin calls are allowed for left hand value", |
278 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
279 | 0 | } |
280 | 188 | return Status::OK(); |
281 | 188 | } |
282 | | |
283 | 467k | CHECKED_STATUS PTExpr::CheckRhsExpr(SemContext *sem_context) { |
284 | | // Check for limitation in QL (Not all expressions are acceptable). |
285 | 467k | switch (op_) { |
286 | 690 | case ExprOperator::kRef: |
287 | | // Only accept column references where they are explicitly allowed. |
288 | 690 | if (sem_context->sem_state() == nullptr || !sem_context->allowing_column_refs()) { |
289 | 23 | return sem_context->Error(this, |
290 | 23 | "Column references are not allowed in this context", |
291 | 23 | ErrorCode::CQL_STATEMENT_INVALID); |
292 | 23 | } |
293 | 667 | FALLTHROUGH_INTENDED; |
294 | 444k | case ExprOperator::kConst: FALLTHROUGH_INTENDED; |
295 | 445k | case ExprOperator::kCollection: FALLTHROUGH_INTENDED; |
296 | 450k | case ExprOperator::kUMinus: FALLTHROUGH_INTENDED; |
297 | 466k | case ExprOperator::kBindVar: FALLTHROUGH_INTENDED; |
298 | 466k | case ExprOperator::kJsonOperatorRef: FALLTHROUGH_INTENDED; |
299 | 466k | case ExprOperator::kBcall: |
300 | 466k | break; |
301 | 0 | default: |
302 | 0 | return sem_context->Error(this, "Operator not allowed as right hand value", |
303 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
304 | 466k | } |
305 | | |
306 | 466k | return Status::OK(); |
307 | 466k | } |
308 | | |
309 | 1 | CHECKED_STATUS PTExpr::CheckCounterUpdateSupport(SemContext *sem_context) const { |
310 | 1 | return sem_context->Error(this, ErrorCode::INVALID_COUNTING_EXPR); |
311 | 1 | } |
312 | | |
313 | | PTExpr::SharedPtr PTExpr::CreateConst(MemoryContext *memctx, |
314 | | YBLocation::SharedPtr loc, |
315 | 113 | PTBaseType::SharedPtr data_type) { |
316 | 113 | switch(data_type->ql_type()->main()) { |
317 | 16 | case DataType::DOUBLE: |
318 | 16 | return PTConstDouble::MakeShared(memctx, loc, 0); |
319 | 6 | case DataType::FLOAT: |
320 | 6 | return PTConstFloat::MakeShared(memctx, loc, 0); |
321 | 9 | case DataType::INT16: |
322 | 9 | return PTConstInt16::MakeShared(memctx, loc, 0); |
323 | 21 | case DataType::INT32: |
324 | 21 | return PTConstInt32::MakeShared(memctx, loc, 0); |
325 | 17 | case DataType::INT64: |
326 | 17 | return PTConstInt::MakeShared(memctx, loc, 0); |
327 | 23 | case DataType::STRING: |
328 | 23 | return PTConstText::MakeShared(memctx, loc, MCMakeShared<MCString>(memctx, "")); |
329 | 2 | case DataType::TIMESTAMP: |
330 | 2 | return PTConstTimestamp::MakeShared(memctx, loc, 0); |
331 | 1 | case DataType::DATE: |
332 | 1 | return PTConstDate::MakeShared(memctx, loc, 0); |
333 | 2 | case DataType::DECIMAL: |
334 | 2 | return PTConstDecimal::MakeShared(memctx, loc, MCMakeShared<MCString>(memctx)); |
335 | 16 | default: |
336 | 16 | LOG(WARNING) << "Unexpected QL type: " << data_type->ql_type()->ToString(); |
337 | 16 | return nullptr; |
338 | 113 | } |
339 | 113 | } |
340 | | |
341 | | //-------------------------------------------------------------------------------------------------- |
342 | | |
343 | | PTLiteralString::PTLiteralString(MCSharedPtr<MCString> value) |
344 | 341k | : PTLiteral<MCSharedPtr<MCString>>(value) { |
345 | 341k | } |
346 | | |
347 | 344k | PTLiteralString::~PTLiteralString() { |
348 | 344k | } |
349 | | |
350 | 3.87M | CHECKED_STATUS PTLiteralString::ToInt64(int64_t *value, bool negate) const { |
351 | 1.57k | auto temp = negate ? CheckedStoll(string("-") + value_->c_str()) |
352 | 3.87M | : CheckedStoll(*value_); |
353 | 3.87M | RETURN_NOT_OK(temp); |
354 | 3.87M | *value = *temp; |
355 | 3.87M | return Status::OK(); |
356 | 3.87M | } |
357 | | |
358 | 1.72k | CHECKED_STATUS PTLiteralString::ToDouble(long double *value, bool negate) const { |
359 | 1.72k | auto temp = CheckedStold(*value_); |
360 | 1.72k | RETURN_NOT_OK(temp); |
361 | 1.71k | *value = negate ? -*temp : *temp; |
362 | 1.71k | return Status::OK(); |
363 | 1.72k | } |
364 | | |
365 | 0 | CHECKED_STATUS PTLiteralString::ToDecimal(util::Decimal *value, bool negate) const { |
366 | 0 | if (negate) { |
367 | 0 | return value->FromString(string("-") + value_->c_str()); |
368 | 0 | } else { |
369 | 0 | return value->FromString(value_->c_str()); |
370 | 0 | } |
371 | 0 | } |
372 | | |
373 | 2.75k | CHECKED_STATUS PTLiteralString::ToDecimal(string *value, bool negate) const { |
374 | 2.75k | util::Decimal d; |
375 | 2.75k | if (negate) { |
376 | 1.05k | RETURN_NOT_OK(d.FromString(string("-") + value_->c_str())); |
377 | 1.69k | } else { |
378 | 1.69k | RETURN_NOT_OK(d.FromString(value_->c_str())); |
379 | 1.69k | } |
380 | 2.75k | *value = d.EncodeToComparable(); |
381 | 2.75k | return Status::OK(); |
382 | 2.75k | } |
383 | | |
384 | 2.10k | CHECKED_STATUS PTLiteralString::ToVarInt(string *value, bool negate) const { |
385 | 2.10k | util::VarInt v; |
386 | 2.10k | if (negate) { |
387 | 861 | RETURN_NOT_OK(v.FromString(string("-") + value_->c_str())); |
388 | 1.24k | } else { |
389 | 1.24k | RETURN_NOT_OK(v.FromString(value_->c_str())); |
390 | 1.24k | } |
391 | 2.10k | *value = v.EncodeToComparable(); |
392 | 2.10k | return Status::OK(); |
393 | 2.10k | } |
394 | | |
395 | 98 | std::string PTLiteralString::ToString() const { |
396 | 98 | return string(value_->c_str()); |
397 | 98 | } |
398 | | |
399 | 177k | CHECKED_STATUS PTLiteralString::ToString(string *value) const { |
400 | 177k | *value = value_->c_str(); |
401 | 177k | return Status::OK(); |
402 | 177k | } |
403 | | |
404 | 1.36k | CHECKED_STATUS PTLiteralString::ToTimestamp(int64_t *value) const { |
405 | 1.32k | *value = VERIFY_RESULT(DateTime::TimestampFromString(value_->c_str())).ToInt64(); |
406 | 1.32k | return Status::OK(); |
407 | 1.36k | } |
408 | | |
409 | 26 | CHECKED_STATUS PTLiteralString::ToDate(uint32_t *value) const { |
410 | 22 | *value = VERIFY_RESULT(DateTime::DateFromString(value_->c_str())); |
411 | 22 | return Status::OK(); |
412 | 26 | } |
413 | | |
414 | 10 | CHECKED_STATUS PTLiteralString::ToTime(int64_t *value) const { |
415 | 5 | *value = VERIFY_RESULT(DateTime::TimeFromString(value_->c_str())); |
416 | 5 | return Status::OK(); |
417 | 10 | } |
418 | | |
419 | 355 | CHECKED_STATUS PTLiteralString::ToInetaddress(InetAddress *value) const { |
420 | 353 | *value = InetAddress(VERIFY_RESULT(HostToAddress(value_->c_str()))); |
421 | 353 | return Status::OK(); |
422 | 355 | } |
423 | | |
424 | | //-------------------------------------------------------------------------------------------------- |
425 | | // Collections. |
426 | | |
427 | | CHECKED_STATUS PTCollectionExpr::InitializeUDTValues(const QLType::SharedPtr& expected_type, |
428 | 232 | ProcessContextBase* process_context) { |
429 | 232 | SCHECK(expected_type->IsUserDefined(), Corruption, "Expected type should be UDT"); |
430 | 232 | SCHECK_EQ(keys_.size(), values_.size(), Corruption, |
431 | 232 | "Expected keys and values to be of the same size"); |
432 | | |
433 | 232 | udtype_field_values_.resize(expected_type->udtype_field_names().size()); |
434 | | // Each literal key/value pair must correspond to a field name/type pair from the UDT |
435 | 232 | auto values_it = values_.begin(); |
436 | 436 | for (const auto& key : keys_) { |
437 | | // All keys must be field refs |
438 | | |
439 | | // TODO (mihnea) Consider unifying handling of field references (for user-defined types) and |
440 | | // column references (for tables) to simplify this path. |
441 | 436 | if (key->opcode() != TreeNodeOpcode::kPTRef) { |
442 | 14 | return process_context->Error(this, |
443 | 14 | "Field names for user-defined types must be field reference", |
444 | 14 | ErrorCode::INVALID_ARGUMENTS); |
445 | 14 | } |
446 | 422 | PTRef* field_ref = down_cast<PTRef*>(key.get()); |
447 | 422 | if (!field_ref->name()->IsSimpleName()) { |
448 | 0 | return process_context->Error(this, |
449 | 0 | "Qualified names not allowed for fields of user-defined types", |
450 | 0 | ErrorCode::INVALID_ARGUMENTS); |
451 | 0 | } |
452 | 422 | string field_name(field_ref->name()->last_name().c_str()); |
453 | | |
454 | | // All keys must be existing field names from the UDT |
455 | 422 | auto field_idx = expected_type->GetUDTypeFieldIdxByName(field_name); |
456 | 422 | if (!field_idx) { |
457 | 0 | return process_context->Error(this, "Invalid field name found for user-defined type instance", |
458 | 0 | ErrorCode::INVALID_ARGUMENTS); |
459 | 0 | } |
460 | | |
461 | | // Setting the corresponding field value |
462 | 422 | udtype_field_values_[*field_idx] = *values_it; |
463 | 422 | values_it++; |
464 | 422 | } |
465 | 218 | return Status::OK(); |
466 | 232 | } |
467 | | |
468 | | PTCollectionExpr::PTCollectionExpr(MemoryContext* memctx, |
469 | | YBLocationPtr loc, |
470 | | const QLTypePtr& ql_type) |
471 | | : PTExpr(memctx, loc, ExprOperator::kCollection, yb::QLOperator::QL_OP_NOOP, |
472 | | client::YBColumnSchema::ToInternalDataType(ql_type), ql_type), |
473 | 1.37k | keys_(memctx), values_(memctx), udtype_field_values_(memctx) {} |
474 | | |
475 | | PTCollectionExpr::PTCollectionExpr(MemoryContext* memctx, YBLocationPtr loc, DataType literal_type) |
476 | 1.32k | : PTCollectionExpr(memctx, loc, QLType::Create(literal_type)) {} Unexecuted instantiation: _ZN2yb2ql16PTCollectionExprC2EPNS_8internal9ArenaBaseINS2_11ArenaTraitsEEENSt3__110shared_ptrINS0_10YBLocationEEENS_8DataTypeE _ZN2yb2ql16PTCollectionExprC1EPNS_8internal9ArenaBaseINS2_11ArenaTraitsEEENSt3__110shared_ptrINS0_10YBLocationEEENS_8DataTypeE Line | Count | Source | 476 | 1.32k | : PTCollectionExpr(memctx, loc, QLType::Create(literal_type)) {} |
|
477 | | |
478 | 2.01k | CHECKED_STATUS PTCollectionExpr::Analyze(SemContext *sem_context) { |
479 | | // Before traversing the expression, check if this whole expression is actually a column. |
480 | 2.01k | if (CheckIndexColumn(sem_context)) { |
481 | 0 | return Status::OK(); |
482 | 0 | } |
483 | | |
484 | 2.01k | RETURN_NOT_OK(CheckOperator(sem_context)); |
485 | 2.01k | const shared_ptr<QLType>& expected_type = sem_context->expr_expected_ql_type(); |
486 | | |
487 | | // If no expected type is given, use type inferred during parsing |
488 | 2.01k | if (expected_type->main() == DataType::UNKNOWN_DATA) { |
489 | 124 | return CheckExpectedTypeCompatibility(sem_context); |
490 | 124 | } |
491 | | |
492 | | // Ensuring expected type is compatible with parsing/literal type. |
493 | 1.89k | auto conversion_mode = QLType::GetConversionMode(expected_type->main(), ql_type_->main()); |
494 | 1.89k | if (conversion_mode > QLType::ConversionMode::kFurtherCheck) { |
495 | 21 | return sem_context->Error(this, ErrorCode::DATATYPE_MISMATCH); |
496 | 21 | } |
497 | | |
498 | 1.87k | const MCSharedPtr<MCString>& bindvar_name = sem_context->bindvar_name(); |
499 | | |
500 | | // Checking type parameters. |
501 | 1.87k | switch (expected_type->main()) { |
502 | 222 | case MAP: { |
503 | 222 | if (ql_type_->main() == SET && values_.size() > 0) { |
504 | 10 | return sem_context->Error(this, ErrorCode::DATATYPE_MISMATCH); |
505 | 10 | } |
506 | | |
507 | | // Process keys and values. |
508 | | // Referencing column in collection is not allowed. |
509 | 212 | SemState sem_state(sem_context); |
510 | 212 | sem_state.set_allowing_column_refs(false); |
511 | | |
512 | 212 | const shared_ptr<QLType>& key_type = expected_type->param_type(0); |
513 | 212 | sem_state.SetExprState( |
514 | 212 | key_type, YBColumnSchema::ToInternalDataType(key_type), |
515 | 212 | bindvar_name, nullptr, NullIsAllowed::kFalse); |
516 | 299 | for (auto& key : keys_) { |
517 | 299 | RETURN_NOT_OK(key->Analyze(sem_context)); |
518 | 272 | RETURN_NOT_OK(key->CheckRhsExpr(sem_context)); |
519 | 272 | } |
520 | | |
521 | 183 | const shared_ptr<QLType>& val_type = expected_type->param_type(1); |
522 | 183 | sem_state.SetExprState( |
523 | 183 | val_type, YBColumnSchema::ToInternalDataType(val_type), |
524 | 183 | bindvar_name, nullptr, NullIsAllowed::kFalse); |
525 | 267 | for (auto& value : values_) { |
526 | 267 | RETURN_NOT_OK(value->Analyze(sem_context)); |
527 | 247 | RETURN_NOT_OK(value->CheckRhsExpr(sem_context)); |
528 | 247 | } |
529 | | |
530 | 163 | sem_state.ResetContextState(); |
531 | 163 | break; |
532 | 183 | } |
533 | 179 | case SET: { |
534 | | // Process values. |
535 | | // Referencing column in collection is not allowed. |
536 | 179 | SemState sem_state(sem_context); |
537 | 179 | sem_state.set_allowing_column_refs(false); |
538 | | |
539 | 179 | const shared_ptr<QLType>& val_type = expected_type->param_type(0); |
540 | 179 | sem_state.SetExprState( |
541 | 179 | val_type, YBColumnSchema::ToInternalDataType(val_type), |
542 | 179 | bindvar_name, nullptr, NullIsAllowed::kFalse); |
543 | 287 | for (auto& elem : values_) { |
544 | 287 | RETURN_NOT_OK(elem->Analyze(sem_context)); |
545 | 252 | RETURN_NOT_OK(elem->CheckRhsExpr(sem_context)); |
546 | 252 | } |
547 | 142 | sem_state.ResetContextState(); |
548 | 142 | break; |
549 | 179 | } |
550 | | |
551 | 834 | case LIST: { |
552 | | // Process values. |
553 | | // Referencing column in collection is not allowed. |
554 | 834 | SemState sem_state(sem_context); |
555 | 834 | sem_state.set_allowing_column_refs(false); |
556 | | |
557 | 834 | const shared_ptr<QLType>& val_type = expected_type->param_type(0); |
558 | | // NULL value in the LIST is allowed for right operand of IN/NOT IN operators only. |
559 | 834 | sem_state.SetExprState( |
560 | 834 | val_type, YBColumnSchema::ToInternalDataType(val_type), |
561 | 834 | bindvar_name, nullptr, NullIsAllowed(is_in_operand())); |
562 | 2.49k | for (auto& elem : values_) { |
563 | 2.49k | RETURN_NOT_OK(elem->Analyze(sem_context)); |
564 | 2.45k | RETURN_NOT_OK(elem->CheckRhsExpr(sem_context)); |
565 | 2.45k | } |
566 | 792 | sem_state.ResetContextState(); |
567 | 792 | break; |
568 | 834 | } |
569 | | |
570 | 222 | case USER_DEFINED_TYPE: { |
571 | | // Process values. |
572 | | // Referencing column in collection is not allowed. |
573 | 222 | SemState sem_state(sem_context); |
574 | 222 | sem_state.set_allowing_column_refs(false); |
575 | | |
576 | 222 | RETURN_NOT_OK(InitializeUDTValues(expected_type, sem_context)); |
577 | 637 | for (size_t i = 0; i < udtype_field_values_.size(); i++) { |
578 | 437 | if (!udtype_field_values_[i]) { |
579 | | // Skip missing values |
580 | 43 | continue; |
581 | 43 | } |
582 | | // Each value should have the corresponding type from the UDT |
583 | 394 | const auto& param_type = expected_type->param_type(i); |
584 | 394 | sem_state.SetExprState(param_type, |
585 | 394 | YBColumnSchema::ToInternalDataType(param_type), |
586 | 394 | bindvar_name); |
587 | 394 | RETURN_NOT_OK(udtype_field_values_[i]->Analyze(sem_context)); |
588 | 386 | RETURN_NOT_OK(udtype_field_values_[i]->CheckRhsExpr(sem_context)); |
589 | 386 | } |
590 | 200 | sem_state.ResetContextState(); |
591 | 200 | break; |
592 | 208 | } |
593 | | |
594 | 414 | case FROZEN: { |
595 | 414 | if (ql_type_->main() == FROZEN) { |
596 | | // Already analyzed (e.g. for indexes), just check if type matches. |
597 | 31 | if (*ql_type_ != *expected_type) { |
598 | 0 | return sem_context->Error(this, ErrorCode::DATATYPE_MISMATCH); |
599 | 0 | } |
600 | 383 | } else { |
601 | 383 | SemState sem_state(sem_context); |
602 | 383 | sem_state.SetExprState(expected_type->param_type(0), |
603 | 383 | YBColumnSchema::ToInternalDataType(expected_type->param_type(0)), |
604 | 383 | bindvar_name); |
605 | 383 | RETURN_NOT_OK(Analyze(sem_context)); |
606 | 337 | sem_state.ResetContextState(); |
607 | 337 | } |
608 | 368 | break; |
609 | 414 | } |
610 | | |
611 | 0 | case TUPLE: |
612 | 0 | return sem_context->Error(this, "Tuple type not supported yet", |
613 | 0 | ErrorCode::FEATURE_NOT_SUPPORTED); |
614 | | |
615 | 0 | default: |
616 | 0 | return sem_context->Error(this, ErrorCode::DATATYPE_MISMATCH); |
617 | 1.66k | } |
618 | | |
619 | | // Assign correct datatype. |
620 | 1.66k | ql_type_ = expected_type; |
621 | 1.66k | internal_type_ = sem_context->expr_expected_internal_type(); |
622 | | |
623 | 1.66k | return Status::OK(); |
624 | 1.66k | } |
625 | | |
626 | | //-------------------------------------------------------------------------------------------------- |
627 | | // Logic expressions consist of the following operators. |
628 | | // ExprOperator::kNot |
629 | | // ExprOperator::kAND |
630 | | // ExprOperator::kOR |
631 | | // ExprOperator::kIsTrue |
632 | | // ExprOperator::kIsFalse |
633 | | |
634 | 33.2k | CHECKED_STATUS PTLogicExpr::SetupSemStateForOp1(SemState *sem_state) { |
635 | | // Expect "bool" datatype for logic expression. |
636 | 33.2k | sem_state->SetExprState(QLType::Create(BOOL), InternalType::kBoolValue); |
637 | | |
638 | | // Pass down the state variables for IF clause "if_state". |
639 | 33.2k | sem_state->CopyPreviousIfState(); |
640 | | |
641 | | // If this is OP_AND, we need to pass down the state variables for where clause "where_state". |
642 | 33.2k | if (ql_op_ == QL_OP_AND) { |
643 | 33.2k | sem_state->CopyPreviousWhereState(); |
644 | 33.2k | } |
645 | 33.2k | return Status::OK(); |
646 | 33.2k | } |
647 | | |
648 | 33.2k | CHECKED_STATUS PTLogicExpr::SetupSemStateForOp2(SemState *sem_state) { |
649 | | // Expect "bool" datatype for logic expression. |
650 | 33.2k | sem_state->SetExprState(QLType::Create(BOOL), InternalType::kBoolValue); |
651 | | |
652 | | // Pass down the state variables for IF clause "if_state". |
653 | 33.2k | sem_state->CopyPreviousIfState(); |
654 | | |
655 | | // If this is OP_AND, we need to pass down the state variables for where clause "where_state". |
656 | 33.2k | if (ql_op_ == QL_OP_AND) { |
657 | 33.1k | sem_state->CopyPreviousWhereState(); |
658 | 33.1k | } |
659 | 33.2k | return Status::OK(); |
660 | 33.2k | } |
661 | | |
662 | | CHECKED_STATUS PTLogicExpr::AnalyzeOperator(SemContext *sem_context, |
663 | 0 | PTExpr::SharedPtr op1) { |
664 | 0 | switch (ql_op_) { |
665 | 0 | case QL_OP_NOT: |
666 | 0 | if (op1->ql_type_id() != BOOL) { |
667 | 0 | return sem_context->Error(this, "Only boolean value is allowed in this context", |
668 | 0 | ErrorCode::INVALID_DATATYPE); |
669 | 0 | } |
670 | 0 | internal_type_ = yb::InternalType::kBoolValue; |
671 | 0 | break; |
672 | |
|
673 | 0 | case QL_OP_IS_TRUE: FALLTHROUGH_INTENDED; |
674 | 0 | case QL_OP_IS_FALSE: |
675 | 0 | return sem_context->Error(this, "Operator not supported yet", |
676 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
677 | 0 | default: |
678 | 0 | LOG(FATAL) << "Invalid operator"; |
679 | 0 | } |
680 | 0 | return Status::OK(); |
681 | 0 | } |
682 | | |
683 | | CHECKED_STATUS PTLogicExpr::AnalyzeOperator(SemContext *sem_context, |
684 | | PTExpr::SharedPtr op1, |
685 | 33.0k | PTExpr::SharedPtr op2) { |
686 | | // Verify the operators. |
687 | 33.0k | DCHECK(ql_op_ == QL_OP_AND || ql_op_ == QL_OP_OR); |
688 | | |
689 | | // "op1" and "op2" must have been analyzed before getting here |
690 | 33.0k | if (op1->ql_type_id() != BOOL) { |
691 | 0 | return sem_context->Error(op1, "Only boolean value is allowed in this context", |
692 | 0 | ErrorCode::INVALID_DATATYPE); |
693 | 0 | } |
694 | 33.0k | if (op2->ql_type_id() != BOOL) { |
695 | 0 | return sem_context->Error(op2, "Only boolean value is allowed in this context", |
696 | 0 | ErrorCode::INVALID_DATATYPE); |
697 | 0 | } |
698 | | |
699 | 33.0k | internal_type_ = yb::InternalType::kBoolValue; |
700 | 33.0k | return Status::OK(); |
701 | 33.0k | } |
702 | | |
703 | | //-------------------------------------------------------------------------------------------------- |
704 | | // Relations expressions: ==, !=, >, >=, between, ... |
705 | | |
706 | 228k | CHECKED_STATUS PTRelationExpr::SetupSemStateForOp1(SemState *sem_state) { |
707 | | // Pass down the state variables for IF clause "if_state". |
708 | 228k | sem_state->CopyPreviousIfState(); |
709 | | |
710 | | // passing down where state |
711 | 228k | sem_state->CopyPreviousWhereState(); |
712 | 228k | sem_state->set_allowing_column_refs(true); |
713 | | // No expectation for operand 1. All types are accepted. |
714 | 228k | return Status::OK(); |
715 | 228k | } |
716 | | |
717 | 228k | CHECKED_STATUS PTRelationExpr::SetupSemStateForOp2(SemState *sem_state) { |
718 | | // The state of operand2 is dependent on operand1. |
719 | 228k | PTExpr::SharedPtr operand1 = op1(); |
720 | 228k | DCHECK_NOTNULL(operand1.get()); |
721 | 228k | sem_state->set_allowing_column_refs(false); |
722 | | |
723 | 228k | switch (ql_op_) { |
724 | 223k | case QL_OP_EQUAL: FALLTHROUGH_INTENDED; |
725 | 223k | case QL_OP_LESS_THAN: FALLTHROUGH_INTENDED; |
726 | 224k | case QL_OP_LESS_THAN_EQUAL: FALLTHROUGH_INTENDED; |
727 | 225k | case QL_OP_GREATER_THAN: FALLTHROUGH_INTENDED; |
728 | 226k | case QL_OP_GREATER_THAN_EQUAL: FALLTHROUGH_INTENDED; |
729 | 226k | case QL_OP_NOT_EQUAL: FALLTHROUGH_INTENDED; |
730 | 226k | case QL_OP_EXISTS: FALLTHROUGH_INTENDED; |
731 | 226k | case QL_OP_NOT_EXISTS: FALLTHROUGH_INTENDED; |
732 | 226k | case QL_OP_BETWEEN: FALLTHROUGH_INTENDED; |
733 | 226k | case QL_OP_NOT_BETWEEN: { |
734 | | // TODO(neil) Indexing processing should be redesigned such that when processing a statement |
735 | | // against an INDEX table, most of these semantic processing shouldn't be done again as they |
736 | | // were already done once again the actual table. |
737 | | |
738 | | // Setup for expression column. |
739 | 226k | if (operand1->index_desc() != nullptr) { |
740 | | // Operand1 is a index column. |
741 | 75 | sem_state->SetExprState(operand1->ql_type(), |
742 | 75 | operand1->internal_type(), |
743 | 75 | operand1->index_name(), |
744 | 75 | operand1->index_desc()); |
745 | 75 | break; |
746 | 75 | } |
747 | | |
748 | | // Setup for table column. |
749 | 226k | if (operand1->expr_op() == ExprOperator::kRef) { |
750 | 225k | const PTRef *ref = static_cast<const PTRef *>(operand1.get()); |
751 | 225k | sem_state->SetExprState(ref->ql_type(), |
752 | 225k | ref->internal_type(), |
753 | 225k | ref->bindvar_name(), |
754 | 225k | ref->desc()); |
755 | 225k | break; |
756 | 225k | } |
757 | | |
758 | | // Setup for other expression. |
759 | 937 | sem_state->SetExprState(operand1->ql_type(), operand1->internal_type()); |
760 | 937 | switch (operand1->expr_op()) { |
761 | 172 | case ExprOperator::kBcall: { |
762 | 172 | PTBcall *bcall = static_cast<PTBcall *>(operand1.get()); |
763 | 172 | DCHECK_NOTNULL(bcall->name().get()); |
764 | 172 | if (strcmp(bcall->name()->c_str(), "token") == 0) { |
765 | 66 | sem_state->set_bindvar_name(PTBindVar::token_bindvar_name()); |
766 | 66 | } |
767 | 172 | if (strcmp(bcall->name()->c_str(), "partition_hash") == 0) { |
768 | 30 | sem_state->set_bindvar_name(PTBindVar::partition_hash_bindvar_name()); |
769 | 30 | } |
770 | 172 | break; |
771 | 0 | } |
772 | | |
773 | 293 | case ExprOperator::kSubColRef: { |
774 | 293 | const PTSubscriptedColumn *ref = static_cast<const PTSubscriptedColumn *>(operand1.get()); |
775 | 293 | if (ref->desc()) { |
776 | 221 | sem_state->set_bindvar_name(PTBindVar::coll_bindvar_name(ref->desc()->name())); |
777 | 72 | } else if (!sem_state->is_uncovered_index_select()) { |
778 | 0 | return STATUS( |
779 | 0 | QLError, "Column doesn't exist", Slice(), QLError(ErrorCode::UNDEFINED_COLUMN)); |
780 | 0 | } // else - this column is uncovered by the Index, skip checks and return OK. |
781 | 293 | break; |
782 | 293 | } |
783 | | |
784 | 343 | case ExprOperator::kJsonOperatorRef: { |
785 | 343 | const PTJsonColumnWithOperators *ref = |
786 | 343 | static_cast<const PTJsonColumnWithOperators*>(operand1.get()); |
787 | 343 | if (ref->desc()) { |
788 | 341 | sem_state->set_bindvar_name(PTBindVar::json_bindvar_name(ref->desc()->name())); |
789 | 2 | } else if (!sem_state->is_uncovered_index_select()) { |
790 | 0 | return STATUS( |
791 | 0 | QLError, "Column doesn't exist", Slice(), QLError(ErrorCode::UNDEFINED_COLUMN)); |
792 | 0 | } // else - this column is uncovered by the Index, skip checks and return OK. |
793 | 343 | break; |
794 | 343 | } |
795 | | |
796 | 0 | default: {} // Use default bindvar name below. |
797 | 937 | } |
798 | | |
799 | 808 | break; |
800 | 937 | } |
801 | | |
802 | 586 | case QL_OP_IN: FALLTHROUGH_INTENDED; |
803 | 712 | case QL_OP_NOT_IN: { |
804 | 712 | auto ql_type = QLType::CreateTypeList(operand1->ql_type()); |
805 | | |
806 | 712 | if (operand1->index_desc() != nullptr) { |
807 | | // Operand1 is a index column. |
808 | 0 | sem_state->SetExprState(operand1->ql_type(), |
809 | 0 | operand1->internal_type(), |
810 | 0 | operand1->index_name(), |
811 | 0 | operand1->index_desc()); |
812 | 712 | } else if (operand1->expr_op() == ExprOperator::kRef) { |
813 | 572 | const PTRef *ref = static_cast<const PTRef *>(operand1.get()); |
814 | 572 | sem_state->SetExprState(ql_type, |
815 | 572 | ref->internal_type(), |
816 | 572 | ref->bindvar_name(), |
817 | 572 | ref->desc()); |
818 | 140 | } else { |
819 | 140 | sem_state->SetExprState(ql_type, operand1->internal_type()); |
820 | 140 | } |
821 | 712 | break; |
822 | 586 | } |
823 | | |
824 | 0 | default: |
825 | 0 | LOG(FATAL) << "Invalid operator" << int(ql_op_); |
826 | 228k | } |
827 | | |
828 | 228k | if (!sem_state->bindvar_name()) { |
829 | 290 | sem_state->set_bindvar_name(PTBindVar::default_bindvar_name()); |
830 | 290 | } |
831 | | |
832 | 228k | return Status::OK(); |
833 | 228k | } |
834 | | |
835 | 0 | CHECKED_STATUS PTRelationExpr::SetupSemStateForOp3(SemState *sem_state) { |
836 | | // The states of operand3 is dependent on operand1 in the same way as op2. |
837 | 0 | return SetupSemStateForOp2(sem_state); |
838 | 0 | } |
839 | | |
840 | 109 | CHECKED_STATUS PTRelationExpr::AnalyzeOperator(SemContext *sem_context) { |
841 | 109 | switch (ql_op_) { |
842 | 25 | case QL_OP_EXISTS: FALLTHROUGH_INTENDED; |
843 | 109 | case QL_OP_NOT_EXISTS: |
844 | 109 | return Status::OK(); |
845 | 0 | default: |
846 | 0 | LOG(FATAL) << "Invalid operator"; |
847 | 109 | } |
848 | 0 | return Status::OK(); |
849 | 109 | } |
850 | | |
851 | | CHECKED_STATUS PTRelationExpr::AnalyzeOperator(SemContext *sem_context, |
852 | 0 | PTExpr::SharedPtr op1) { |
853 | | // "op1" must have been analyzed before getting here |
854 | 0 | switch (ql_op_) { |
855 | 0 | case QL_OP_IS_NULL: FALLTHROUGH_INTENDED; |
856 | 0 | case QL_OP_IS_NOT_NULL: |
857 | 0 | return sem_context->Error(this, "Operator not supported yet", |
858 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
859 | 0 | default: |
860 | 0 | LOG(FATAL) << "Invalid operator" << int(ql_op_); |
861 | 0 | } |
862 | |
|
863 | 0 | return Status::OK(); |
864 | 0 | } |
865 | | |
866 | | CHECKED_STATUS PTRelationExpr::AnalyzeOperator(SemContext *sem_context, |
867 | | PTExpr::SharedPtr op1, |
868 | 227k | PTExpr::SharedPtr op2) { |
869 | | // "op1" and "op2" must have been analyzed before getting here |
870 | 227k | switch (ql_op_) { |
871 | 542 | case QL_OP_NOT_EQUAL: FALLTHROUGH_INTENDED; |
872 | 223k | case QL_OP_EQUAL: |
873 | 223k | RETURN_NOT_OK(op1->CheckLhsExpr(sem_context)); |
874 | 223k | RETURN_NOT_OK(op2->CheckRhsExpr(sem_context)); |
875 | 223k | RETURN_NOT_OK(CheckEqualityOperands(sem_context, op1, op2)); |
876 | 223k | internal_type_ = yb::InternalType::kBoolValue; |
877 | 223k | break; |
878 | 895 | case QL_OP_LESS_THAN: FALLTHROUGH_INTENDED; |
879 | 2.43k | case QL_OP_GREATER_THAN: FALLTHROUGH_INTENDED; |
880 | 2.80k | case QL_OP_LESS_THAN_EQUAL: FALLTHROUGH_INTENDED; |
881 | 3.25k | case QL_OP_GREATER_THAN_EQUAL: |
882 | 3.25k | RETURN_NOT_OK(op1->CheckLhsExpr(sem_context)); |
883 | 3.25k | RETURN_NOT_OK(op2->CheckRhsExpr(sem_context)); |
884 | 3.25k | RETURN_NOT_OK(CheckInequalityOperands(sem_context, op1, op2)); |
885 | 3.24k | internal_type_ = yb::InternalType::kBoolValue; |
886 | 3.24k | break; |
887 | | |
888 | 584 | case QL_OP_IN: |
889 | 708 | case QL_OP_NOT_IN: |
890 | 708 | RETURN_NOT_OK(op1->CheckLhsExpr(sem_context)); |
891 | 700 | RETURN_NOT_OK(op2->CheckRhsExpr(sem_context)); |
892 | | // For IN operator, we check compatibility between op1's type and op2's value_type. |
893 | 700 | if (!sem_context->IsComparable(op1->ql_type_id(), op2->ql_type()->values_type()->main())) { |
894 | 42 | return sem_context->Error(this, "Cannot compare values of these datatypes", |
895 | 42 | ErrorCode::INCOMPARABLE_DATATYPES); |
896 | 42 | } |
897 | 658 | break; |
898 | | |
899 | 0 | default: |
900 | 0 | return sem_context->Error(this, "Operator not supported yet", |
901 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
902 | 228k | } |
903 | | |
904 | | // Collecting scan information if its state is set. |
905 | 228k | SelectScanInfo *scan_state = sem_context->scan_state(); |
906 | 228k | if (scan_state != nullptr) { |
907 | | // Add reference to expressions and operators in WHERE clause for indexing analysis. |
908 | 106k | if (scan_state->analyze_where()) { |
909 | 106k | if (op1->index_desc()) { |
910 | 0 | RETURN_NOT_OK(scan_state->AddWhereExpr(sem_context, this, op1->index_desc(), op2)); |
911 | |
|
912 | 106k | } else if (op1->expr_op() == ExprOperator::kRef) { |
913 | 106k | const PTRef *ref = static_cast<const PTRef *>(op1.get()); |
914 | 106k | RETURN_NOT_OK(scan_state->AddWhereExpr(sem_context, this, ref->desc(), op2)); |
915 | | |
916 | 462 | } else if (op1->expr_op() == ExprOperator::kSubColRef) { |
917 | 106 | const PTSubscriptedColumn *ref = static_cast<const PTSubscriptedColumn *>(op1.get()); |
918 | 106 | RETURN_NOT_OK(scan_state->AddWhereExpr(sem_context, this, ref->desc(), op2, ref->args())); |
919 | | |
920 | 356 | } else if (op1->expr_op() == ExprOperator::kJsonOperatorRef) { |
921 | 118 | const PTJsonColumnWithOperators *ref = |
922 | 118 | static_cast<const PTJsonColumnWithOperators*>(op1.get()); |
923 | 118 | RETURN_NOT_OK(scan_state->AddWhereExpr(sem_context, this, ref->desc(), op2, |
924 | 118 | ref->operators())); |
925 | 118 | } |
926 | 106k | } |
927 | | |
928 | | // Add filtering expressions in IF clause for indexing analysis. |
929 | 106k | if (scan_state->analyze_if()) { |
930 | 206 | if (op1->index_desc() || |
931 | 206 | op1->expr_op() == ExprOperator::kRef || |
932 | 114 | op1->expr_op() == ExprOperator::kSubColRef || |
933 | 206 | op1->expr_op() == ExprOperator::kJsonOperatorRef) { |
934 | 206 | RETURN_NOT_OK(scan_state->AddFilteringExpr(sem_context, this)); |
935 | 206 | } |
936 | 206 | } |
937 | 106k | } |
938 | | |
939 | 228k | WhereExprState *where_state = sem_context->where_state(); |
940 | 228k | if (where_state != nullptr) { |
941 | | // CheckLhsExpr already checks that this is either kRef or kBcall |
942 | 121k | DCHECK(op1->index_desc() != nullptr || |
943 | 121k | op1->expr_op() == ExprOperator::kRef || |
944 | 121k | op1->expr_op() == ExprOperator::kSubColRef || |
945 | 121k | op1->expr_op() == ExprOperator::kJsonOperatorRef || |
946 | 121k | op1->expr_op() == ExprOperator::kBcall); |
947 | 121k | if (op1->index_desc()) { |
948 | 75 | return where_state->AnalyzeColumnOp(sem_context, this, op1->index_desc(), op2); |
949 | 121k | } else if (op1->expr_op() == ExprOperator::kRef) { |
950 | 120k | const PTRef *ref = static_cast<const PTRef *>(op1.get()); |
951 | 120k | return where_state->AnalyzeColumnOp(sem_context, this, ref->desc(), op2); |
952 | 469 | } else if (op1->expr_op() == ExprOperator::kSubColRef) { |
953 | 176 | const PTSubscriptedColumn *ref = static_cast<const PTSubscriptedColumn *>(op1.get()); |
954 | 176 | return where_state->AnalyzeColumnOp(sem_context, this, ref->desc(), op2, ref->args()); |
955 | 293 | } else if (op1->expr_op() == ExprOperator::kJsonOperatorRef) { |
956 | 76 | const PTJsonColumnWithOperators *ref = |
957 | 76 | static_cast<const PTJsonColumnWithOperators*>(op1.get()); |
958 | | |
959 | 76 | return where_state->AnalyzeColumnOp(sem_context, this, ref->desc(), op2, ref->operators()); |
960 | 217 | } else if (op1->expr_op() == ExprOperator::kBcall) { |
961 | 94 | const PTBcall *bcall = static_cast<const PTBcall *>(op1.get()); |
962 | 94 | if (strcmp(bcall->name()->c_str(), "token") == 0 || |
963 | 61 | strcmp(bcall->name()->c_str(), "partition_hash") == 0) { |
964 | 48 | const PTToken *token = static_cast<const PTToken *>(bcall); |
965 | 48 | if (token->is_partition_key_ref()) { |
966 | 48 | return where_state->AnalyzePartitionKeyOp(sem_context, this, op2); |
967 | 0 | } else { |
968 | 0 | return sem_context->Error(this, |
969 | 0 | "token/partition_hash calls need to reference partition key", |
970 | 0 | ErrorCode::FEATURE_NOT_SUPPORTED); |
971 | 0 | } |
972 | 46 | } else if (strcmp(bcall->name()->c_str(), "ttl") == 0 || |
973 | 38 | strcmp(bcall->name()->c_str(), "writetime") == 0 || |
974 | 46 | strcmp(bcall->name()->c_str(), "cql_cast") == 0) { |
975 | 46 | PTBcall::SharedPtr bcall_shared = std::make_shared<PTBcall>(*bcall); |
976 | 46 | return where_state->AnalyzeColumnFunction(sem_context, this, op2, bcall_shared); |
977 | 0 | } else { |
978 | 0 | return sem_context->Error(loc(), "Builtin call not allowed in where clause", |
979 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
980 | 0 | } |
981 | 107k | } |
982 | 121k | } |
983 | | |
984 | 107k | if (sem_context->idx_predicate_state() != nullptr) { |
985 | 180 | DCHECK(op1->index_desc() != nullptr || |
986 | 180 | op1->expr_op() == ExprOperator::kRef || |
987 | 180 | op1->expr_op() == ExprOperator::kSubColRef || |
988 | 180 | op1->expr_op() == ExprOperator::kJsonOperatorRef || |
989 | 180 | op1->expr_op() == ExprOperator::kBcall); |
990 | | // TODO(Piyush): Block mutable functions only. Allow all other functions. |
991 | | |
992 | | // Allow only expressions involving columns. Block subscripted/json col+operators. |
993 | 180 | if (op1->expr_op() != ExprOperator::kRef) { |
994 | 3 | return sem_context->Error(this, |
995 | 3 | "Parital index where clause only allows operators on table columns", |
996 | 3 | ErrorCode::FEATURE_NOT_SUPPORTED); |
997 | 3 | } |
998 | 107k | } |
999 | | |
1000 | 107k | return Status::OK(); |
1001 | 107k | } |
1002 | | |
1003 | | CHECKED_STATUS PTRelationExpr::AnalyzeOperator(SemContext *sem_context, |
1004 | | PTExpr::SharedPtr op1, |
1005 | | PTExpr::SharedPtr op2, |
1006 | 0 | PTExpr::SharedPtr op3) { |
1007 | | // "op1", "op2", and "op3" must have been analyzed before getting here |
1008 | 0 | switch (ql_op_) { |
1009 | 0 | case QL_OP_BETWEEN: FALLTHROUGH_INTENDED; |
1010 | 0 | case QL_OP_NOT_BETWEEN: |
1011 | 0 | RETURN_NOT_OK(op1->CheckLhsExpr(sem_context)); |
1012 | 0 | RETURN_NOT_OK(op2->CheckRhsExpr(sem_context)); |
1013 | 0 | RETURN_NOT_OK(op3->CheckRhsExpr(sem_context)); |
1014 | 0 | RETURN_NOT_OK(CheckInequalityOperands(sem_context, op1, op2)); |
1015 | 0 | RETURN_NOT_OK(CheckInequalityOperands(sem_context, op1, op3)); |
1016 | 0 | internal_type_ = yb::InternalType::kBoolValue; |
1017 | 0 | break; |
1018 | |
|
1019 | 0 | default: |
1020 | 0 | LOG(FATAL) << "Invalid operator " << QLOperator_Name(ql_op_); |
1021 | 0 | } |
1022 | |
|
1023 | 0 | return Status::OK(); |
1024 | 0 | } |
1025 | | |
1026 | 0 | string PTRelationExpr::QLName(QLNameOption option) const { |
1027 | 0 | switch (ql_op_) { |
1028 | 0 | case QL_OP_NOOP: |
1029 | 0 | return "NO OP"; |
1030 | | |
1031 | | // Logic operators that take one operand. |
1032 | 0 | case QL_OP_NOT: |
1033 | 0 | return string("NOT ") + op1()->QLName(option); |
1034 | 0 | case QL_OP_IS_TRUE: |
1035 | 0 | return op1()->QLName(option) + "IS TRUE"; |
1036 | 0 | case QL_OP_IS_FALSE: |
1037 | 0 | return op1()->QLName(option) + "IS FALSE"; |
1038 | | |
1039 | | // Logic operators that take two or more operands. |
1040 | 0 | case QL_OP_AND: |
1041 | 0 | return op1()->QLName(option) + " AND " + op2()->QLName(option); |
1042 | 0 | case QL_OP_OR: |
1043 | 0 | return op1()->QLName(option) + " OR " + op2()->QLName(option); |
1044 | | |
1045 | | // Relation operators that take one operand. |
1046 | 0 | case QL_OP_IS_NULL: |
1047 | 0 | return op1()->QLName(option) + " IS NULL"; |
1048 | 0 | case QL_OP_IS_NOT_NULL: |
1049 | 0 | return op1()->QLName(option) + " IS NOT NULL"; |
1050 | | |
1051 | | // Relation operators that take two operands. |
1052 | 0 | case QL_OP_EQUAL: |
1053 | 0 | return op1()->QLName(option) + " == " + op2()->QLName(option); |
1054 | 0 | case QL_OP_LESS_THAN: |
1055 | 0 | return op1()->QLName(option) + " < " + op2()->QLName(option); |
1056 | 0 | case QL_OP_LESS_THAN_EQUAL: |
1057 | 0 | return op1()->QLName(option) + " <= " + op2()->QLName(option); |
1058 | 0 | case QL_OP_GREATER_THAN: |
1059 | 0 | return op1()->QLName(option) + " > " + op2()->QLName(option); |
1060 | 0 | case QL_OP_GREATER_THAN_EQUAL: |
1061 | 0 | return op1()->QLName(option) + " >= " + op2()->QLName(option); |
1062 | 0 | case QL_OP_NOT_EQUAL: |
1063 | 0 | return op1()->QLName(option) + " != " + op2()->QLName(option); |
1064 | | |
1065 | 0 | case QL_OP_LIKE: |
1066 | 0 | return op1()->QLName(option) + " LIKE " + op2()->QLName(option); |
1067 | 0 | case QL_OP_NOT_LIKE: |
1068 | 0 | return op1()->QLName(option) + " NOT LIKE " + |
1069 | 0 | op2()->QLName(option); |
1070 | 0 | case QL_OP_IN: |
1071 | 0 | return op1()->QLName(option) + " IN " + op2()->QLName(option); |
1072 | 0 | case QL_OP_NOT_IN: |
1073 | 0 | return op1()->QLName(option) + " NOT IN " + op2()->QLName(option); |
1074 | | |
1075 | | // Relation operators that take three operands. |
1076 | 0 | case QL_OP_BETWEEN: |
1077 | 0 | return op1()->QLName(option) + " BETWEEN " + |
1078 | 0 | op2()->QLName(option) + " AND " + |
1079 | 0 | op3()->QLName(option); |
1080 | 0 | case QL_OP_NOT_BETWEEN: |
1081 | 0 | return op1()->QLName(option) + " NOT BETWEEN " + |
1082 | 0 | op2()->QLName(option) + " AND " + |
1083 | 0 | op3()->QLName(option); |
1084 | | |
1085 | | // Operators that take no operand. For use in "if" clause only currently. |
1086 | 0 | case QL_OP_EXISTS: |
1087 | 0 | return "EXISTS"; |
1088 | 0 | case QL_OP_NOT_EXISTS: |
1089 | 0 | return "NOT EXISTS"; |
1090 | 0 | } |
1091 | | |
1092 | 0 | return "expr"; |
1093 | 0 | } |
1094 | | |
1095 | 50 | const ColumnDesc *PTExpr::GetColumnDesc(const SemContext *sem_context) { |
1096 | 50 | MCString expr_name(MangledName().c_str(), sem_context->PTempMem()); |
1097 | 50 | return GetColumnDesc(sem_context, expr_name, sem_context->current_dml_stmt()); |
1098 | 50 | } |
1099 | | |
1100 | | const ColumnDesc *PTExpr::GetColumnDesc(const SemContext *sem_context, |
1101 | 614k | const MCString& col_name) const { |
1102 | 614k | if (sem_context->selecting_from_index()) { |
1103 | | // Mangle column name when selecting from IndexTable. |
1104 | 3.62k | MCString mangled_name(YcqlName::MangleColumnName(col_name.c_str()).c_str(), |
1105 | 3.62k | sem_context->PTempMem()); |
1106 | 3.62k | return GetColumnDesc(sem_context, mangled_name, sem_context->current_dml_stmt()); |
1107 | 3.62k | } |
1108 | | |
1109 | 610k | return GetColumnDesc(sem_context, col_name, sem_context->current_dml_stmt()); |
1110 | 610k | } |
1111 | | |
1112 | | const ColumnDesc *PTExpr::GetColumnDesc(const SemContext *sem_context, |
1113 | | const MCString& desc_name, |
1114 | 614k | PTDmlStmt *stmt) const { |
1115 | 614k | SelectScanInfo *scan_state = sem_context->scan_state(); |
1116 | 614k | if (scan_state) { |
1117 | | // Get column from scan_state when analyze index for scanning. |
1118 | 107k | return scan_state->GetColumnDesc(sem_context, desc_name); |
1119 | 107k | } |
1120 | | |
1121 | 507k | if (stmt) { |
1122 | | // Get column from DML statement when compiling a DML statement. |
1123 | 505k | return stmt->GetColumnDesc(sem_context, desc_name); |
1124 | 505k | } |
1125 | | |
1126 | | // Get column from symbol table in context. |
1127 | 2.46k | return sem_context->GetColumnDesc(desc_name); |
1128 | 2.46k | } |
1129 | | |
1130 | | //-------------------------------------------------------------------------------------------------- |
1131 | | |
1132 | 4.92k | CHECKED_STATUS PTOperatorExpr::SetupSemStateForOp1(SemState *sem_state) { |
1133 | 4.92k | switch (op_) { |
1134 | 4.92k | case ExprOperator::kUMinus: |
1135 | 4.92k | case ExprOperator::kAlias: |
1136 | 4.92k | sem_state->CopyPreviousStates(); |
1137 | 4.92k | break; |
1138 | | |
1139 | 0 | default: |
1140 | 0 | LOG(FATAL) << "Invalid operator " << int(op_); |
1141 | 4.92k | } |
1142 | | |
1143 | 4.92k | return Status::OK(); |
1144 | 4.92k | } |
1145 | | |
1146 | | CHECKED_STATUS PTOperatorExpr::AnalyzeOperator(SemContext *sem_context, |
1147 | 4.92k | PTExpr::SharedPtr op1) { |
1148 | 4.92k | switch (op_) { |
1149 | 4.92k | case ExprOperator::kUMinus: |
1150 | | // "op1" must have been analyzed before we get here. |
1151 | | // Check to make sure that it is allowed in this context. |
1152 | 4.92k | if (op1->expr_op() != ExprOperator::kConst) { |
1153 | 4 | return sem_context->Error(this, "Only numeric constant is allowed in this context", |
1154 | 4 | ErrorCode::FEATURE_NOT_SUPPORTED); |
1155 | 4 | } |
1156 | 4.91k | if (!QLType::IsNumeric(op1->ql_type_id())) { |
1157 | 0 | return sem_context->Error(this, "Only numeric data type is allowed in this context", |
1158 | 0 | ErrorCode::INVALID_DATATYPE); |
1159 | 0 | } |
1160 | | |
1161 | | // Type resolution: (-x) should have the same datatype as (x). |
1162 | 4.91k | ql_type_ = op1->ql_type(); |
1163 | 4.91k | internal_type_ = op1->internal_type(); |
1164 | 4.91k | break; |
1165 | | |
1166 | 0 | default: |
1167 | 0 | LOG(FATAL) << "Invalid operator" << int(op_); |
1168 | 4.92k | } |
1169 | | |
1170 | 4.91k | return Status::OK(); |
1171 | 4.92k | } |
1172 | | |
1173 | | //-------------------------------------------------------------------------------------------------- |
1174 | | |
1175 | | PTRef::PTRef(MemoryContext *memctx, |
1176 | | YBLocation::SharedPtr loc, |
1177 | | const PTQualifiedName::SharedPtr& name) |
1178 | | : PTOperator0(memctx, loc, ExprOperator::kRef, yb::QLOperator::QL_OP_NOOP), |
1179 | | name_(name), |
1180 | 505k | desc_(nullptr) { |
1181 | 505k | } |
1182 | | |
1183 | 503k | PTRef::~PTRef() { |
1184 | 503k | } |
1185 | | |
1186 | 792k | std::string PTRef::QLName(QLNameOption option) const { |
1187 | 792k | if (option == QLNameOption::kMetadataName) { |
1188 | | // Should only be called after the descriptor is loaded from the catalog by Analyze(). |
1189 | 0 | CHECK(desc_) << "Metadata is not yet loaded to this node"; |
1190 | 316 | return desc_->MetadataName(); |
1191 | 316 | } |
1192 | | |
1193 | 791k | if (option == QLNameOption::kMangledName) { |
1194 | 16.0k | return YcqlName::MangleColumnName(name_->QLName()); |
1195 | 16.0k | } |
1196 | | |
1197 | 775k | return name_->QLName(); |
1198 | 775k | } |
1199 | | |
1200 | 226k | const MCSharedPtr<MCString>& PTRef::bindvar_name() const { |
1201 | 226k | return name_->bindvar_name(); |
1202 | 226k | } |
1203 | | |
1204 | 613k | CHECKED_STATUS PTRef::AnalyzeOperator(SemContext *sem_context) { |
1205 | 18.4E | DCHECK(name_ != nullptr) << "Reference column is not specified"; |
1206 | | |
1207 | | // Look for a column descriptor from symbol table. |
1208 | 613k | RETURN_NOT_OK(name_->Analyze(sem_context)); |
1209 | 613k | if (!name_->IsSimpleName()) { |
1210 | 3 | return sem_context->Error(this, "Qualified name not allowed for column reference", |
1211 | 3 | ErrorCode::SQL_STATEMENT_INVALID); |
1212 | 3 | } |
1213 | 613k | desc_ = GetColumnDesc(sem_context, name_->last_name()); |
1214 | 613k | if (desc_ == nullptr) { |
1215 | | // If this is a nested select from an uncovered index/partial index, |
1216 | | // ignore column that is uncovered/only in partial index predicate and not in index cols. |
1217 | 106 | LOG(INFO) << "Column " << name_->last_name() << " not found"; |
1218 | 106 | return sem_context->IsUncoveredIndexSelect() || sem_context->IsPartialIndexSelect() |
1219 | 80 | ? Status::OK() |
1220 | 26 | : sem_context->Error(this, "Column doesn't exist", ErrorCode::UNDEFINED_COLUMN); |
1221 | 106 | } |
1222 | | |
1223 | | // Type resolution: Ref(x) should have the same datatype as (x). |
1224 | 612k | internal_type_ = desc_->internal_type(); |
1225 | 612k | ql_type_ = desc_->ql_type(); |
1226 | 612k | return Status::OK(); |
1227 | 612k | } |
1228 | | |
1229 | 227k | CHECKED_STATUS PTRef::CheckLhsExpr(SemContext *sem_context) { |
1230 | | // When CQL IF clause is being processed. In that case, disallow reference to primary key columns |
1231 | | // and counters. No error checking is needed when processing SELECT against INDEX table because |
1232 | | // we already check it against the UserTable. |
1233 | 227k | if (sem_context->processing_if_clause() && !sem_context->selecting_from_index()) { |
1234 | 163 | if (desc_->is_primary() && !sem_context->void_primary_key_condition()) { |
1235 | 15 | return sem_context->Error(this, "Primary key column reference is not allowed in if clause", |
1236 | 15 | ErrorCode::CQL_STATEMENT_INVALID); |
1237 | 15 | } |
1238 | 148 | if (desc_->is_counter()) { |
1239 | 2 | return sem_context->Error(this, "Counter column reference is not allowed in if clause", |
1240 | 2 | ErrorCode::CQL_STATEMENT_INVALID); |
1241 | 2 | } |
1242 | 227k | } |
1243 | | |
1244 | | // Only hash/static columns are supported in the where clause of SELECT DISTINCT. |
1245 | 227k | if (sem_context->where_state() != nullptr) { |
1246 | 120k | const PTDmlStmt *dml = sem_context->current_dml_stmt(); |
1247 | 120k | if (dml != nullptr && dml->opcode() == TreeNodeOpcode::kPTSelectStmt && |
1248 | 106k | down_cast<const PTSelectStmt*>(dml)->distinct() && |
1249 | 20 | !desc_->is_hash() && !desc_->is_static()) { |
1250 | 3 | return sem_context->Error(this, |
1251 | 3 | "Non-partition/static column reference is not supported in the " |
1252 | 3 | "where clause of a SELECT DISTINCT statement", |
1253 | 3 | ErrorCode::CQL_STATEMENT_INVALID); |
1254 | 3 | } |
1255 | 227k | } |
1256 | | |
1257 | 227k | return Status::OK(); |
1258 | 227k | } |
1259 | | |
1260 | 0 | void PTRef::PrintSemanticAnalysisResult(SemContext *sem_context) { |
1261 | 0 | VLOG(3) << "SEMANTIC ANALYSIS RESULT (" << *loc_ << "):\n" << "Not yet avail"; |
1262 | 0 | } |
1263 | | |
1264 | | PTJsonOperator::PTJsonOperator(MemoryContext *memctx, |
1265 | | YBLocation::SharedPtr loc, |
1266 | | const JsonOperator& json_operator, |
1267 | | const PTExpr::SharedPtr& arg) |
1268 | | : PTExpr(memctx, loc, ExprOperator::kJsonOperatorRef, yb::QLOperator::QL_OP_NOOP, |
1269 | | InternalType::kJsonbValue, DataType::JSONB), |
1270 | | json_operator_(json_operator), |
1271 | 1.61k | arg_(arg) { |
1272 | 1.61k | } |
1273 | | |
1274 | 1.55k | PTJsonOperator::~PTJsonOperator() { |
1275 | 1.55k | } |
1276 | | |
1277 | 1.93k | Status PTJsonOperator::Analyze(SemContext *sem_context) { |
1278 | 1.93k | return arg_->Analyze(sem_context); |
1279 | 1.93k | } |
1280 | | |
1281 | | //-------------------------------------------------------------------------------------------------- |
1282 | | |
1283 | | PTJsonColumnWithOperators::PTJsonColumnWithOperators(MemoryContext *memctx, |
1284 | | YBLocation::SharedPtr loc, |
1285 | | const PTQualifiedName::SharedPtr& name, |
1286 | | const PTExprListNode::SharedPtr& operators) |
1287 | | : PTOperator0(memctx, loc, ExprOperator::kJsonOperatorRef, yb::QLOperator::QL_OP_NOOP), |
1288 | | name_(name), |
1289 | 860 | operators_(operators) { |
1290 | 860 | } |
1291 | | |
1292 | 854 | PTJsonColumnWithOperators::~PTJsonColumnWithOperators() { |
1293 | 854 | } |
1294 | | |
1295 | 1.06k | CHECKED_STATUS PTJsonColumnWithOperators::AnalyzeOperator(SemContext *sem_context) { |
1296 | | // Look for a column descriptor from symbol table. |
1297 | 1.06k | RETURN_NOT_OK(name_->Analyze(sem_context)); |
1298 | 1.06k | desc_ = GetColumnDesc(sem_context, name_->last_name()); |
1299 | 1.06k | if (desc_ == nullptr) { |
1300 | | // If this is a nested select from an uncovered index, ignore column that is uncovered. |
1301 | 3 | return sem_context->IsUncoveredIndexSelect() |
1302 | 2 | ? Status::OK() |
1303 | 1 | : sem_context->Error(this, "Column doesn't exist", ErrorCode::UNDEFINED_COLUMN); |
1304 | 3 | } |
1305 | | |
1306 | 1.06k | SemState sem_state(sem_context); |
1307 | | |
1308 | 1.06k | if (!desc_->ql_type()->IsJson()) { |
1309 | 2 | return sem_context->Error(this, "Column provided is not json data type", |
1310 | 2 | ErrorCode::CQL_STATEMENT_INVALID); |
1311 | 2 | } |
1312 | | |
1313 | 1.06k | if (operators_->size() == 0) { |
1314 | 0 | return sem_context->Error(this, "No operators provided.", |
1315 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
1316 | 0 | } |
1317 | | |
1318 | | // Analyze each operator. |
1319 | 1.06k | RETURN_NOT_OK(operators_->Analyze(sem_context)); |
1320 | | |
1321 | | // Check the last operator to determine type. |
1322 | 1.06k | auto json_operator = std::dynamic_pointer_cast<PTJsonOperator>( |
1323 | 1.06k | operators_->node_list().back())->json_operator(); |
1324 | | |
1325 | 1.06k | if (json_operator == JsonOperator::JSON_OBJECT) { |
1326 | 142 | ql_type_ = QLType::Create(DataType::JSONB); |
1327 | 142 | internal_type_ = InternalType::kJsonbValue; |
1328 | 921 | } else if (json_operator == JsonOperator::JSON_TEXT) { |
1329 | 921 | ql_type_ = QLType::Create(DataType::STRING); |
1330 | 921 | internal_type_ = InternalType::kStringValue; |
1331 | 0 | } else { |
1332 | 0 | return sem_context->Error(this, "Invalid operator.", |
1333 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
1334 | 0 | } |
1335 | | |
1336 | 1.06k | return Status::OK(); |
1337 | 1.06k | } |
1338 | | |
1339 | 406 | CHECKED_STATUS PTJsonColumnWithOperators::CheckLhsExpr(SemContext *sem_context) { |
1340 | 406 | return Status::OK(); |
1341 | 406 | } |
1342 | | |
1343 | 1.95k | std::string PTJsonColumnWithOperators::QLName(QLNameOption option) const { |
1344 | 1.95k | string qlname; |
1345 | 1.95k | if (option == QLNameOption::kMetadataName) { |
1346 | 0 | DCHECK(desc_) << "Metadata is not yet loaded to this node"; |
1347 | 0 | qlname = desc_->MetadataName(); |
1348 | 1.95k | } else if (option == QLNameOption::kMangledName) { |
1349 | 744 | qlname = YcqlName::MangleColumnName(name_->QLName()); |
1350 | 1.20k | } else { |
1351 | 1.20k | qlname = name_->QLName(); |
1352 | 1.20k | } |
1353 | | |
1354 | 2.87k | for (PTExpr::SharedPtr expr : operators_->node_list()) { |
1355 | 2.87k | qlname += expr->QLName(option); |
1356 | 2.87k | } |
1357 | 1.95k | return qlname; |
1358 | 1.95k | } |
1359 | | |
1360 | | //-------------------------------------------------------------------------------------------------- |
1361 | | |
1362 | | PTSubscriptedColumn::PTSubscriptedColumn(MemoryContext *memctx, |
1363 | | YBLocation::SharedPtr loc, |
1364 | | const PTQualifiedName::SharedPtr& name, |
1365 | | const PTExprListNode::SharedPtr& args) |
1366 | | : PTOperator0(memctx, loc, ExprOperator::kSubColRef, yb::QLOperator::QL_OP_NOOP), |
1367 | | name_(name), |
1368 | | args_(args), |
1369 | 201 | desc_(nullptr) { |
1370 | 201 | } |
1371 | | |
1372 | 158 | PTSubscriptedColumn::~PTSubscriptedColumn() { |
1373 | 158 | } |
1374 | | |
1375 | 425 | CHECKED_STATUS PTSubscriptedColumn::AnalyzeOperator(SemContext *sem_context) { |
1376 | | |
1377 | | // Check if this refers to the whole table (SELECT *). |
1378 | 425 | if (name_ == nullptr) { |
1379 | 0 | return sem_context->Error(this, "Cannot do type resolution for wildcard reference (SELECT *)", |
1380 | 0 | ErrorCode::SQL_STATEMENT_INVALID); |
1381 | 0 | } |
1382 | | |
1383 | | // Look for a column descriptor from symbol table. |
1384 | 425 | RETURN_NOT_OK(name_->Analyze(sem_context)); |
1385 | 425 | desc_ = GetColumnDesc(sem_context, name_->last_name()); |
1386 | 425 | if (desc_ == nullptr) { |
1387 | | // If this is a nested select from an uncovered index, ignore column that is uncovered. |
1388 | 72 | return sem_context->IsUncoveredIndexSelect() |
1389 | 72 | ? Status::OK() |
1390 | 0 | : sem_context->Error(this, "Column doesn't exist", ErrorCode::UNDEFINED_COLUMN); |
1391 | 72 | } |
1392 | | |
1393 | 353 | SemState sem_state(sem_context); |
1394 | | |
1395 | 353 | auto curr_ytype = desc_->ql_type(); |
1396 | 353 | auto curr_itype = desc_->internal_type(); |
1397 | | |
1398 | 353 | if (args_ != nullptr) { |
1399 | 353 | for (const auto &arg : args_->node_list()) { |
1400 | 353 | if (curr_ytype->keys_type() == nullptr) { |
1401 | 8 | return sem_context->Error(this, "Columns with elementary types cannot take arguments", |
1402 | 8 | ErrorCode::CQL_STATEMENT_INVALID); |
1403 | 8 | } |
1404 | | |
1405 | 345 | sem_state.SetExprState(curr_ytype->keys_type(), |
1406 | 345 | client::YBColumnSchema::ToInternalDataType(curr_ytype->keys_type())); |
1407 | 345 | RETURN_NOT_OK(arg->Analyze(sem_context)); |
1408 | | |
1409 | 345 | curr_ytype = curr_ytype->values_type(); |
1410 | 345 | curr_itype = client::YBColumnSchema::ToInternalDataType(curr_ytype); |
1411 | 345 | } |
1412 | 353 | } |
1413 | | |
1414 | | // Type resolution: Ref(x) should have the same datatype as (x). |
1415 | 345 | ql_type_ = curr_ytype; |
1416 | 345 | internal_type_ = curr_itype; |
1417 | | |
1418 | 345 | return Status::OK(); |
1419 | 353 | } |
1420 | | |
1421 | 0 | const MCSharedPtr<MCString>& PTSubscriptedColumn::bindvar_name() const { |
1422 | 0 | return name_->bindvar_name(); |
1423 | 0 | } |
1424 | | |
1425 | 409 | CHECKED_STATUS PTSubscriptedColumn::CheckLhsExpr(SemContext *sem_context) { |
1426 | | // If where_state is null, we are processing the IF clause. In that case, disallow reference to |
1427 | | // primary key columns. |
1428 | 409 | if (sem_context->where_state() == nullptr && |
1429 | 233 | desc_->is_primary() && !sem_context->void_primary_key_condition()) { |
1430 | 0 | return sem_context->Error(this, "Primary key column reference is not allowed in if expression", |
1431 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
1432 | 0 | } |
1433 | 409 | return Status::OK(); |
1434 | 409 | } |
1435 | | |
1436 | 0 | void PTSubscriptedColumn::PrintSemanticAnalysisResult(SemContext *sem_context) { |
1437 | 0 | VLOG(3) << "SEMANTIC ANALYSIS RESULT (" << *loc_ << "):\n" << "Not yet avail"; |
1438 | 0 | } |
1439 | | |
1440 | | //-------------------------------------------------------------------------------------------------- |
1441 | | |
1442 | | PTAllColumns::PTAllColumns(MemoryContext *memctx, YBLocation::SharedPtr loc) |
1443 | | : PTOperator0(memctx, loc, ExprOperator::kRef, yb::QLOperator::QL_OP_NOOP), |
1444 | 157k | columns_(memctx) { |
1445 | 157k | } |
1446 | | |
1447 | 158k | PTAllColumns::~PTAllColumns() { |
1448 | 158k | } |
1449 | | |
1450 | 155k | CHECKED_STATUS PTAllColumns::AnalyzeOperator(SemContext *sem_context) { |
1451 | | // Make sure '*' is used only in 'SELECT *' statement. |
1452 | 155k | const PTDmlStmt *stmt = sem_context->current_dml_stmt(); |
1453 | 155k | if (stmt == nullptr || |
1454 | 155k | stmt->opcode() != TreeNodeOpcode::kPTSelectStmt || |
1455 | 155k | static_cast<const PTSelectStmt*>(stmt)->selected_exprs().size() > 1) { |
1456 | 0 | return sem_context->Error(loc(), "Cannot use '*' expression in this context", |
1457 | 0 | ErrorCode::CQL_STATEMENT_INVALID); |
1458 | 0 | } |
1459 | | |
1460 | 155k | const auto* select_stmt = static_cast<const PTSelectStmt*>(stmt); |
1461 | 155k | columns_.clear(); |
1462 | 155k | columns_.reserve(select_stmt->column_map().size()); |
1463 | 1.72M | for (const auto& pair : select_stmt->column_map()) { |
1464 | 1.72M | columns_.emplace_back(pair.second); |
1465 | 1.72M | } |
1466 | | |
1467 | | // For 'select * ... ' using index only, sort them in the same order as the table columns so that |
1468 | | // the selected columns are returned in the proper order. |
1469 | 155k | if (select_stmt->table()->IsIndex()) { |
1470 | 95 | MCUnorderedMap<int, int> map(sem_context->PTempMem()); // Map of column_id -> indexed_column_id |
1471 | 226 | for (const auto& column : select_stmt->table()->index_info().columns()) { |
1472 | 226 | map.emplace(column.column_id, column.indexed_column_id); |
1473 | 226 | } |
1474 | 95 | std::sort(columns_.begin(), columns_.end(), |
1475 | 150 | [&map](const ColumnDesc& a, const ColumnDesc& b) { |
1476 | 150 | return map[a.id()] < map[b.id()]; |
1477 | 150 | }); |
1478 | 155k | } else { |
1479 | 155k | std::sort(columns_.begin(), columns_.end(), |
1480 | 5.17M | [](const ColumnDesc& a, const ColumnDesc& b) { |
1481 | 5.17M | return a.id() < b.id(); |
1482 | 5.17M | }); |
1483 | 155k | } |
1484 | | |
1485 | | // Note to server that all column are referenced by this statement. |
1486 | 155k | sem_context->current_dml_stmt()->AddRefForAllColumns(); |
1487 | | |
1488 | | // TODO(Mihnea) See if TUPLE datatype can be used here. |
1489 | | // '*' should be of TUPLE type, but we use the following workaround for now. |
1490 | 155k | ql_type_ = QLType::Create(DataType::NULL_VALUE_TYPE); |
1491 | 155k | internal_type_ = InternalType::kListValue; |
1492 | 155k | return Status::OK(); |
1493 | 155k | } |
1494 | | |
1495 | | //-------------------------------------------------------------------------------------------------- |
1496 | | |
1497 | | PTExprAlias::PTExprAlias(MemoryContext *memctx, |
1498 | | YBLocation::SharedPtr loc, |
1499 | | const PTExpr::SharedPtr& expr, |
1500 | | const MCSharedPtr<MCString>& alias) |
1501 | | : PTOperator1(memctx, loc, ExprOperator::kAlias, yb::QLOperator::QL_OP_NOOP, expr), |
1502 | 2 | alias_(alias) { |
1503 | 2 | } |
1504 | | |
1505 | 2 | PTExprAlias::~PTExprAlias() { |
1506 | 2 | } |
1507 | | |
1508 | 2 | CHECKED_STATUS PTExprAlias::SetupSemStateForOp1(SemState *sem_state) { |
1509 | 2 | sem_state->set_allowing_aggregate(sem_state->previous_state()->allowing_aggregate()); |
1510 | 2 | return Status::OK(); |
1511 | 2 | } |
1512 | | |
1513 | 2 | CHECKED_STATUS PTExprAlias::AnalyzeOperator(SemContext *sem_context, PTExpr::SharedPtr op1) { |
1514 | | // Type resolution: Alias of (x) should have the same datatype as (x). |
1515 | 2 | ql_type_ = op1->ql_type(); |
1516 | 2 | internal_type_ = op1->internal_type(); |
1517 | 2 | return Status::OK(); |
1518 | 2 | } |
1519 | | |
1520 | | //-------------------------------------------------------------------------------------------------- |
1521 | | |
1522 | | PTBindVar::PTBindVar(MemoryContext *memctx, |
1523 | | YBLocation::SharedPtr loc, |
1524 | | const MCSharedPtr<MCString>& name) |
1525 | | : PTExpr(memctx, loc, ExprOperator::kBindVar), |
1526 | 14.3k | name_(name) { |
1527 | 14.3k | } |
1528 | | |
1529 | | PTBindVar::PTBindVar(MemoryContext *memctx, |
1530 | | YBLocation::SharedPtr loc, |
1531 | | PTConstVarInt::SharedPtr user_pos) |
1532 | | : PTExpr(memctx, loc, ExprOperator::kBindVar), |
1533 | 24 | user_pos_(user_pos) { |
1534 | 24 | } |
1535 | | |
1536 | 9.52k | PTBindVar::~PTBindVar() { |
1537 | 9.52k | } |
1538 | | |
1539 | 16.2k | CHECKED_STATUS PTBindVar::Analyze(SemContext *sem_context) { |
1540 | | // Before traversing the expression, check if this whole expression is actually a column. |
1541 | 16.2k | if (CheckIndexColumn(sem_context)) { |
1542 | 0 | return Status::OK(); |
1543 | 0 | } |
1544 | | |
1545 | 16.2k | RETURN_NOT_OK(CheckOperator(sem_context)); |
1546 | | |
1547 | 16.2k | if (name_ == nullptr) { |
1548 | 13.7k | name_ = sem_context->bindvar_name(); |
1549 | 13.7k | } |
1550 | | |
1551 | 16.2k | if (user_pos_ != nullptr) { |
1552 | 21 | int64_t pos = 0; |
1553 | 21 | if (!user_pos_->ToInt64(&pos, false).ok()) { |
1554 | 1 | return sem_context->Error(this, "Bind position is invalid!", |
1555 | 1 | ErrorCode::INVALID_ARGUMENTS); |
1556 | 1 | } |
1557 | | |
1558 | 20 | if (pos <= 0) { |
1559 | 1 | return sem_context->Error(this, "Bind variable position should be positive!", |
1560 | 1 | ErrorCode::INVALID_ARGUMENTS); |
1561 | 1 | } |
1562 | | // Convert from 1 based to 0 based. |
1563 | 19 | set_pos(pos - 1); |
1564 | 19 | } |
1565 | | |
1566 | 16.2k | if (sem_context->expr_expected_ql_type()->main() == DataType::UNKNOWN_DATA) { |
1567 | | // By default bind variables are compatible with any type. |
1568 | 37 | ql_type_ = QLType::Create(NULL_VALUE_TYPE); |
1569 | 16.2k | } else { |
1570 | 16.2k | ql_type_ = sem_context->expr_expected_ql_type(); |
1571 | 16.2k | } |
1572 | | |
1573 | 16.2k | internal_type_ = sem_context->expr_expected_internal_type(); |
1574 | 16.2k | expected_internal_type_ = internal_type_; |
1575 | 16.2k | hash_col_ = sem_context->hash_col(); |
1576 | 16.2k | if (hash_col_ != nullptr) { |
1577 | 7.19k | DCHECK(sem_context->current_dml_stmt() != nullptr); |
1578 | 7.19k | sem_context->current_dml_stmt()->AddHashColumnBindVar(this); |
1579 | 7.19k | } |
1580 | | |
1581 | 16.2k | return Status::OK(); |
1582 | 16.2k | } |
1583 | | |
1584 | 0 | void PTBindVar::PrintSemanticAnalysisResult(SemContext *sem_context) { |
1585 | 0 | VLOG(3) << "SEMANTIC ANALYSIS RESULT (" << *loc_ << "):\n" << "Not yet avail"; |
1586 | 0 | } |
1587 | | |
1588 | 28 | std::string PTBindVar::bcall_arg_bindvar_name(const std::string& bcall_name, size_t arg_position) { |
1589 | 28 | return strings::Substitute("arg$0(system.$1)", arg_position, bcall_name); |
1590 | 28 | } |
1591 | | |
1592 | | // The name Cassandra uses for binding the collection elements. |
1593 | 221 | std::string PTBindVar::coll_bindvar_name(const std::string& col_name) { |
1594 | 221 | return strings::Substitute("value($0)", col_name); |
1595 | 221 | } |
1596 | | |
1597 | | // The name for binding the JSON attributes. |
1598 | 341 | std::string PTBindVar::json_bindvar_name(const std::string& col_name) { |
1599 | 341 | return strings::Substitute("json_attr($0)", col_name); |
1600 | 341 | } |
1601 | | |
1602 | | } // namespace ql |
1603 | | } // namespace yb |