/Users/deen/code/yugabyte-db/src/yb/common/ql_expr.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //-------------------------------------------------------------------------------------------------- |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | //-------------------------------------------------------------------------------------------------- |
4 | | |
5 | | #include "yb/common/ql_expr.h" |
6 | | |
7 | | #include "yb/common/jsonb.h" |
8 | | #include "yb/common/pgsql_protocol.pb.h" |
9 | | #include "yb/common/ql_bfunc.h" |
10 | | #include "yb/common/ql_value.h" |
11 | | #include "yb/common/schema.h" |
12 | | |
13 | | #include "yb/util/result.h" |
14 | | |
15 | | namespace yb { |
16 | | |
17 | | namespace { |
18 | | |
19 | | constexpr size_t kInvalidIndex = std::numeric_limits<size_t>::max(); |
20 | | |
21 | | } |
22 | | |
23 | 4.95M | bfql::TSOpcode QLExprExecutor::GetTSWriteInstruction(const QLExpressionPB& ql_expr) const { |
24 | | // "kSubDocInsert" instructs the tablet server to insert a new value or replace an existing value. |
25 | 4.95M | if (ql_expr.has_tscall()) { |
26 | 48 | return static_cast<bfql::TSOpcode>(ql_expr.tscall().opcode()); |
27 | 48 | } |
28 | 4.95M | return bfql::TSOpcode::kScalarInsert; |
29 | 4.95M | } |
30 | | |
31 | | //-------------------------------------------------------------------------------------------------- |
32 | | |
33 | | CHECKED_STATUS QLExprExecutor::EvalExpr(const QLExpressionPB& ql_expr, |
34 | | const QLTableRow& table_row, |
35 | | QLExprResultWriter result_writer, |
36 | 42.0M | const Schema *schema) { |
37 | 42.0M | switch (ql_expr.expr_case()) { |
38 | 6.06M | case QLExpressionPB::ExprCase::kValue: |
39 | 6.06M | result_writer.SetExisting(&ql_expr.value()); |
40 | 6.06M | break; |
41 | | |
42 | 35.8M | case QLExpressionPB::ExprCase::kColumnId: |
43 | 35.8M | RETURN_NOT_OK(table_row.ReadColumn(ql_expr.column_id(), result_writer)); |
44 | 35.8M | break; |
45 | | |
46 | 18.0k | case QLExpressionPB::ExprCase::kJsonColumn: { |
47 | 18.0k | QLExprResult temp; |
48 | 18.0k | const QLJsonColumnOperationsPB& json_ops = ql_expr.json_column(); |
49 | 18.0k | RETURN_NOT_OK(table_row.ReadColumn(json_ops.column_id(), temp.Writer())); |
50 | 18.0k | if (temp.IsNull()) { |
51 | 217 | result_writer.SetNull(); |
52 | 17.8k | } else { |
53 | 17.8k | common::Jsonb jsonb; |
54 | 17.8k | temp.MoveToJsonb(&jsonb); |
55 | 17.8k | RETURN_NOT_OK(jsonb.ApplyJsonbOperators(json_ops, &result_writer.NewValue())); |
56 | 17.8k | } |
57 | 18.0k | break; |
58 | 18.0k | } |
59 | | |
60 | 195 | case QLExpressionPB::ExprCase::kSubscriptedCol: |
61 | 195 | if (table_row.IsEmpty()) { |
62 | 0 | result_writer.SetNull(); |
63 | 195 | } else { |
64 | 195 | QLExprResult index_arg; |
65 | 195 | const QLSubscriptedColPB& subcol = ql_expr.subscripted_col(); |
66 | 195 | RETURN_NOT_OK(EvalExpr(subcol.subscript_args(0), table_row, index_arg.Writer())); |
67 | 195 | RETURN_NOT_OK(table_row.ReadSubscriptedColumn(subcol, index_arg.Value(), result_writer)); |
68 | 195 | } |
69 | 195 | break; |
70 | | |
71 | 728 | case QLExpressionPB::ExprCase::kBfcall: |
72 | 728 | return EvalBFCall(ql_expr.bfcall(), table_row, &result_writer.NewValue()); |
73 | | |
74 | 22.6k | case QLExpressionPB::ExprCase::kTscall: |
75 | 22.6k | return EvalTSCall(ql_expr.tscall(), table_row, &result_writer.NewValue(), schema); |
76 | | |
77 | 0 | case QLExpressionPB::ExprCase::kCondition: |
78 | 0 | return EvalCondition(ql_expr.condition(), table_row, &result_writer.NewValue()); |
79 | | |
80 | 0 | case QLExpressionPB::ExprCase::kBocall: FALLTHROUGH_INTENDED; |
81 | 0 | case QLExpressionPB::ExprCase::kBindId: FALLTHROUGH_INTENDED; |
82 | 1 | case QLExpressionPB::ExprCase::EXPR_NOT_SET: |
83 | 1 | result_writer.SetNull(); |
84 | 42.0M | } |
85 | 41.9M | return Status::OK(); |
86 | 42.0M | } |
87 | | |
88 | | //-------------------------------------------------------------------------------------------------- |
89 | | |
90 | | CHECKED_STATUS QLExprExecutor::EvalExpr(QLExpressionPB* ql_expr, |
91 | | const QLTableRow& table_row, |
92 | 6.24M | const Schema *schema) { |
93 | 6.24M | if (!ql_expr->has_value()) { |
94 | 22 | QLExprResult temp; |
95 | 22 | RETURN_NOT_OK(EvalExpr(*ql_expr, table_row, temp.Writer(), schema)); |
96 | 22 | temp.MoveTo(ql_expr->mutable_value()); |
97 | 22 | } |
98 | 6.24M | return Status::OK(); |
99 | 6.24M | } |
100 | | |
101 | | CHECKED_STATUS QLExprExecutor::EvalExpr(const PgsqlExpressionPB& ql_expr, |
102 | | const QLTableRow& table_row, |
103 | | QLExprResultWriter result_writer, |
104 | 240M | const Schema *schema) { |
105 | 240M | return EvalExpr(ql_expr, &table_row, result_writer, schema); |
106 | 240M | } |
107 | | |
108 | | //-------------------------------------------------------------------------------------------------- |
109 | | |
110 | | CHECKED_STATUS QLExprExecutor::ReadExprValue(const QLExpressionPB& ql_expr, |
111 | | const QLTableRow& table_row, |
112 | 0 | QLExprResultWriter result_writer) { |
113 | 0 | if (ql_expr.expr_case() == QLExpressionPB::ExprCase::kTscall) { |
114 | 0 | return ReadTSCallValue(ql_expr.tscall(), table_row, result_writer); |
115 | 0 | } else { |
116 | 0 | return EvalExpr(ql_expr, table_row, result_writer); |
117 | 0 | } |
118 | 0 | } |
119 | | |
120 | | //-------------------------------------------------------------------------------------------------- |
121 | | |
122 | | CHECKED_STATUS QLExprExecutor::EvalBFCall(const QLBCallPB& bfcall, |
123 | | const QLTableRow& table_row, |
124 | 728 | QLValue *result) { |
125 | | // TODO(neil) |
126 | | // - Use TSOpode for collection expression if only TabletServer can execute. |
127 | | // OR |
128 | | // - Introduce BuiltinOperator in addition to builtin function. Use builtin operators for all |
129 | | // special operations including collection operations. That way, we don't need special cases. |
130 | | |
131 | | // Special cases: for collection operations of the form "cref = cref +/- <value>" we avoid |
132 | | // reading column cref and instead tell doc writer to modify it in-place. |
133 | | // "AddMapMap" |
134 | | // "AddSetSet" |
135 | | // "SubMapSet" |
136 | | // "SubSetSet" |
137 | | // "AddListList" |
138 | | // "SubListList" |
139 | | |
140 | 728 | const bfql::BFOpcode bf_opcode = static_cast<bfql::BFOpcode>(bfcall.opcode()); |
141 | | // First evaluate the arguments. |
142 | 728 | vector<QLValue> args(bfcall.operands().size()); |
143 | 728 | int arg_index = 0; |
144 | 728 | QLExprResult temp; |
145 | 787 | for (auto operand : bfcall.operands()) { |
146 | 787 | RETURN_NOT_OK(EvalExpr(operand, table_row, temp.Writer())); |
147 | 783 | temp.MoveTo(args[arg_index++].mutable_value()); |
148 | 783 | } |
149 | | |
150 | | // Execute the builtin call associated with the given opcode. |
151 | 724 | return QLBfunc::Exec(bf_opcode, &args, result); |
152 | 728 | } |
153 | | |
154 | | //-------------------------------------------------------------------------------------------------- |
155 | | |
156 | | CHECKED_STATUS QLExprExecutor::EvalTSCall(const QLBCallPB& ql_expr, |
157 | | const QLTableRow& table_row, |
158 | | QLValue *result, |
159 | 0 | const Schema *schema) { |
160 | 0 | result->SetNull(); |
161 | 0 | return STATUS(RuntimeError, "Only tablet server can execute this operator"); |
162 | 0 | } |
163 | | |
164 | | CHECKED_STATUS QLExprExecutor::ReadTSCallValue(const QLBCallPB& ql_expr, |
165 | | const QLTableRow& table_row, |
166 | 0 | QLExprResultWriter result_writer) { |
167 | 0 | result_writer.SetNull(); |
168 | 0 | return STATUS(RuntimeError, "Only tablet server can execute this operator"); |
169 | 0 | } |
170 | | |
171 | | //-------------------------------------------------------------------------------------------------- |
172 | | |
173 | | CHECKED_STATUS QLExprExecutor::EvalCondition(const QLConditionPB& condition, |
174 | | const QLTableRow& table_row, |
175 | 667k | bool* result) { |
176 | 667k | QLValue result_pb; |
177 | 667k | RETURN_NOT_OK(EvalCondition(condition, table_row, &result_pb)); |
178 | 667k | *result = result_pb.bool_value(); |
179 | 667k | return Status::OK(); |
180 | 667k | } |
181 | | |
182 | | template <class Operands> |
183 | | Result<bool> In( |
184 | 914 | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row) { |
185 | 914 | QLExprResult left, right; |
186 | 914 | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); |
187 | | |
188 | 2.34k | for (const QLValuePB& elem : right.Value().list_value().elems()) { |
189 | 2.34k | if (!Comparable(elem, left.Value())) { |
190 | 0 | return STATUS(RuntimeError, "values not comparable"); |
191 | 0 | } |
192 | 2.34k | if (elem == left.Value()) { |
193 | 767 | return true; |
194 | 767 | } |
195 | 2.34k | } |
196 | | |
197 | 147 | return false; |
198 | 914 | } _ZN2yb2InIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowE Line | Count | Source | 184 | 914 | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row) { | 185 | 914 | QLExprResult left, right; | 186 | 914 | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 187 | | | 188 | 2.34k | for (const QLValuePB& elem : right.Value().list_value().elems()) { | 189 | 2.34k | if (!Comparable(elem, left.Value())) { | 190 | 0 | return STATUS(RuntimeError, "values not comparable"); | 191 | 0 | } | 192 | 2.34k | if (elem == left.Value()) { | 193 | 767 | return true; | 194 | 767 | } | 195 | 2.34k | } | 196 | | | 197 | 147 | return false; | 198 | 914 | } |
Unexecuted instantiation: _ZN2yb2InIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowE |
199 | | |
200 | | template <class Operands, class Op> |
201 | | Result<bool> EvalRelationalOp( |
202 | 1.10M | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { |
203 | 1.10M | QLExprResult left, right; |
204 | 1.10M | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); |
205 | 1.10M | if (!Comparable(left.Value(), right.Value())) { |
206 | 0 | return STATUS(RuntimeError, "values not comparable"); |
207 | 0 | } |
208 | 1.10M | return op(left.Value(), right.Value()); |
209 | 1.10M | } _ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEENSt3__18equal_toIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Line | Count | Source | 202 | 195k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 195k | QLExprResult left, right; | 204 | 195k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 195k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 195k | return op(left.Value(), right.Value()); | 209 | 195k | } |
_ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEENSt3__14lessIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Line | Count | Source | 202 | 419k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 419k | QLExprResult left, right; | 204 | 419k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 419k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 419k | return op(left.Value(), right.Value()); | 209 | 419k | } |
_ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEENSt3__110less_equalIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Line | Count | Source | 202 | 28.0k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 28.0k | QLExprResult left, right; | 204 | 28.0k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 28.0k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 28.0k | return op(left.Value(), right.Value()); | 209 | 28.0k | } |
_ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEENSt3__17greaterIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Line | Count | Source | 202 | 429k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 429k | QLExprResult left, right; | 204 | 429k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 429k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 429k | return op(left.Value(), right.Value()); | 209 | 429k | } |
_ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEENSt3__113greater_equalIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Line | Count | Source | 202 | 29.2k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 29.2k | QLExprResult left, right; | 204 | 29.2k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 29.2k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 29.2k | return op(left.Value(), right.Value()); | 209 | 29.2k | } |
_ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEENSt3__112not_equal_toIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Line | Count | Source | 202 | 1.95k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 1.95k | QLExprResult left, right; | 204 | 1.95k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 1.95k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 1.95k | return op(left.Value(), right.Value()); | 209 | 1.95k | } |
_ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEENSt3__18equal_toIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Line | Count | Source | 202 | 62 | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 62 | QLExprResult left, right; | 204 | 62 | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 62 | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 62 | return op(left.Value(), right.Value()); | 209 | 62 | } |
Unexecuted instantiation: _ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEENSt3__14lessIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Unexecuted instantiation: _ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEENSt3__110less_equalIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Unexecuted instantiation: _ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEENSt3__17greaterIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Unexecuted instantiation: _ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEENSt3__113greater_equalIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ Unexecuted instantiation: _ZN2yb16EvalRelationalOpIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEENSt3__112not_equal_toIvEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowERKT0_ |
210 | | |
211 | | template<bool Value, class Operands> |
212 | | Result<bool> Is( |
213 | 0 | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row) { |
214 | 0 | QLExprResult temp; |
215 | 0 | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, temp.Writer())); |
216 | 0 | if (temp.Value().value_case() != InternalType::kBoolValue) { |
217 | 0 | return STATUS(RuntimeError, "not a bool value"); |
218 | 0 | } |
219 | 0 | return !IsNull(temp.Value()) && temp.Value().bool_value() == Value; |
220 | 0 | } Unexecuted instantiation: _ZN2yb2IsILb1EN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT0_RKNS_10QLTableRowE Unexecuted instantiation: _ZN2yb2IsILb0EN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT0_RKNS_10QLTableRowE Unexecuted instantiation: _ZN2yb2IsILb1EN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT0_RKNS_10QLTableRowE Unexecuted instantiation: _ZN2yb2IsILb0EN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT0_RKNS_10QLTableRowE |
221 | | |
222 | | template<class Operands> |
223 | | Result<bool> Between( |
224 | 0 | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row) { |
225 | 0 | CHECK_EQ(operands.size(), 3); |
226 | 0 | QLExprResult temp, lower, upper; |
227 | 0 | RETURN_NOT_OK(EvalOperands( |
228 | 0 | executor, operands, table_row, temp.Writer(), lower.Writer(), upper.Writer())); |
229 | 0 | if (!Comparable(temp.Value(), lower.Value()) || !Comparable(temp.Value(), upper.Value())) { |
230 | 0 | return STATUS(RuntimeError, "values not comparable"); |
231 | 0 | } |
232 | 0 | return temp.Value() >= lower.Value() && temp.Value() <= upper.Value(); |
233 | 0 | } Unexecuted instantiation: _ZN2yb7BetweenIN6google8protobuf16RepeatedPtrFieldINS_14QLExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowE Unexecuted instantiation: _ZN2yb7BetweenIN6google8protobuf16RepeatedPtrFieldINS_17PgsqlExpressionPBEEEEENS_6ResultIbEEPNS_14QLExprExecutorERKT_RKNS_10QLTableRowE |
234 | | |
235 | | CHECKED_STATUS QLExprExecutor::EvalCondition(const QLConditionPB& condition, |
236 | | const QLTableRow& table_row, |
237 | 1.69M | QLValue *result) { |
238 | 1.69M | #define QL_EVALUATE_RELATIONAL_OP(op) \ |
239 | 1.10M | result->set_bool_value(VERIFY_RESULT(EvalRelationalOp(this, operands, table_row, op))); \ |
240 | 1.10M | return Status::OK(); |
241 | | |
242 | 1.69M | QLExprResult temp; |
243 | 1.69M | const auto& operands = condition.operands(); |
244 | 1.69M | switch (condition.op()) { |
245 | 0 | case QL_OP_NOT: { |
246 | 0 | CHECK_EQ(operands.size(), 1); |
247 | 0 | CHECK_EQ(operands.Get(0).expr_case(), QLExpressionPB::ExprCase::kCondition); |
248 | 0 | QLValue sub_result; |
249 | 0 | RETURN_NOT_OK(EvalCondition(operands.Get(0).condition(), table_row, &sub_result)); |
250 | 0 | result->set_bool_value(!sub_result.bool_value()); |
251 | 0 | return Status::OK(); |
252 | 0 | } |
253 | |
|
254 | 0 | case QL_OP_IS_NULL: |
255 | 0 | CHECK_EQ(operands.size(), 1); |
256 | 0 | RETURN_NOT_OK(EvalExpr(operands.Get(0), table_row, temp.Writer())); |
257 | 0 | result->set_bool_value(IsNull(temp.Value())); |
258 | 0 | return Status::OK(); |
259 | |
|
260 | 0 | case QL_OP_IS_NOT_NULL: |
261 | 0 | CHECK_EQ(operands.size(), 1); |
262 | 0 | RETURN_NOT_OK(EvalExpr(operands.Get(0), table_row, temp.Writer())); |
263 | 0 | result->set_bool_value(!IsNull(temp.Value())); |
264 | 0 | return Status::OK(); |
265 | |
|
266 | 0 | case QL_OP_IS_TRUE: |
267 | 0 | result->set_bool_value(VERIFY_RESULT(Is<true>(this, operands, table_row))); |
268 | 0 | return Status::OK(); |
269 | |
|
270 | 0 | case QL_OP_IS_FALSE: |
271 | 0 | result->set_bool_value(VERIFY_RESULT(Is<false>(this, operands, table_row))); |
272 | 0 | return Status::OK(); |
273 | |
|
274 | 195k | case QL_OP_EQUAL: |
275 | 195k | QL_EVALUATE_RELATIONAL_OP(std::equal_to<>()); |
276 | |
|
277 | 419k | case QL_OP_LESS_THAN: |
278 | 419k | QL_EVALUATE_RELATIONAL_OP(std::less<>()); |
279 | |
|
280 | 28.0k | case QL_OP_LESS_THAN_EQUAL: |
281 | 28.0k | QL_EVALUATE_RELATIONAL_OP(std::less_equal<>()); |
282 | |
|
283 | 429k | case QL_OP_GREATER_THAN: |
284 | 429k | QL_EVALUATE_RELATIONAL_OP(std::greater<>()); |
285 | |
|
286 | 29.2k | case QL_OP_GREATER_THAN_EQUAL: |
287 | 29.2k | QL_EVALUATE_RELATIONAL_OP(std::greater_equal<>()); |
288 | |
|
289 | 1.95k | case QL_OP_NOT_EQUAL: |
290 | 1.95k | QL_EVALUATE_RELATIONAL_OP(std::not_equal_to<>()); |
291 | |
|
292 | 591k | case QL_OP_AND: |
293 | 591k | CHECK_GT(operands.size(), 0); |
294 | 1.02M | for (const auto &operand : operands) { |
295 | 1.02M | CHECK_EQ(operand.expr_case(), QLExpressionPB::ExprCase::kCondition); |
296 | 1.02M | RETURN_NOT_OK(EvalCondition(operand.condition(), table_row, result)); |
297 | 1.02M | if (!result->bool_value()) { |
298 | 143k | break; |
299 | 143k | } |
300 | 1.02M | } |
301 | 591k | return Status::OK(); |
302 | | |
303 | 174 | case QL_OP_OR: |
304 | 174 | CHECK_GT(operands.size(), 0); |
305 | 278 | for (const auto &operand : operands) { |
306 | 278 | CHECK_EQ(operand.expr_case(), QLExpressionPB::ExprCase::kCondition); |
307 | 278 | RETURN_NOT_OK(EvalCondition(operand.condition(), table_row, result)); |
308 | 278 | if (result->bool_value()) { |
309 | 115 | break; |
310 | 115 | } |
311 | 278 | } |
312 | 174 | return Status::OK(); |
313 | | |
314 | 0 | case QL_OP_BETWEEN: |
315 | 0 | result->set_bool_value(VERIFY_RESULT(Between(this, operands, table_row))); |
316 | 0 | return Status::OK(); |
317 | |
|
318 | 0 | case QL_OP_NOT_BETWEEN: |
319 | 0 | result->set_bool_value(!VERIFY_RESULT(Between(this, operands, table_row))); |
320 | 0 | return Status::OK(); |
321 | | |
322 | | // When a row exists, the primary key columns are always populated in the row (value-map) by |
323 | | // DocRowwiseIterator and only when it exists. Therefore, the row exists if and only if |
324 | | // the row (value-map) is not empty. |
325 | 24 | case QL_OP_EXISTS: |
326 | 24 | result->set_bool_value(!table_row.IsEmpty()); |
327 | 24 | return Status::OK(); |
328 | |
|
329 | 70 | case QL_OP_NOT_EXISTS: |
330 | 70 | result->set_bool_value(table_row.IsEmpty()); |
331 | 70 | return Status::OK(); |
332 | |
|
333 | 882 | case QL_OP_IN: |
334 | 882 | CHECK_EQ(operands.size(), 2); |
335 | 882 | result->set_bool_value(VERIFY_RESULT(In(this, operands, table_row))); |
336 | 882 | return Status::OK(); |
337 | | |
338 | 28 | case QL_OP_NOT_IN: |
339 | 28 | CHECK_EQ(operands.size(), 2); |
340 | 28 | result->set_bool_value(!VERIFY_RESULT(In(this, operands, table_row))); |
341 | 28 | return Status::OK(); |
342 | | |
343 | 0 | case QL_OP_LIKE: FALLTHROUGH_INTENDED; |
344 | 0 | case QL_OP_NOT_LIKE: |
345 | 0 | LOG(ERROR) << "Internal error: illegal or unknown operator " << condition.op(); |
346 | 0 | break; |
347 | |
|
348 | 0 | case QL_OP_NOOP: |
349 | 0 | break; |
350 | 0 | } |
351 | | |
352 | 0 | result->SetNull(); |
353 | 0 | return STATUS(RuntimeError, "Internal error: illegal or unknown operator"); |
354 | |
|
355 | 0 | #undef QL_EVALUATE_RELATIONAL_OP |
356 | 0 | } |
357 | | |
358 | | //-------------------------------------------------------------------------------------------------- |
359 | | |
360 | 10.7M | bfpg::TSOpcode QLExprExecutor::GetTSWriteInstruction(const PgsqlExpressionPB& ql_expr) const { |
361 | | // "kSubDocInsert" instructs the tablet server to insert a new value or replace an existing value. |
362 | 10.7M | if (ql_expr.has_tscall()) { |
363 | 11.4k | return static_cast<bfpg::TSOpcode>(ql_expr.tscall().opcode()); |
364 | 11.4k | } |
365 | 10.7M | return bfpg::TSOpcode::kScalarInsert; |
366 | 10.7M | } |
367 | | |
368 | | //-------------------------------------------------------------------------------------------------- |
369 | | |
370 | | CHECKED_STATUS QLExprExecutor::EvalExpr(const PgsqlExpressionPB& ql_expr, |
371 | | const QLTableRow* table_row, |
372 | | QLExprResultWriter result_writer, |
373 | 240M | const Schema *schema) { |
374 | 240M | switch (ql_expr.expr_case()) { |
375 | 10.2M | case PgsqlExpressionPB::ExprCase::kValue: |
376 | 10.2M | result_writer.SetExisting(&ql_expr.value()); |
377 | 10.2M | break; |
378 | | |
379 | 228M | case PgsqlExpressionPB::ExprCase::kColumnId: |
380 | 228M | return EvalColumnRef(ql_expr.column_id(), table_row, result_writer); |
381 | | |
382 | 0 | case PgsqlExpressionPB::ExprCase::kBfcall: |
383 | 0 | return EvalBFCall(ql_expr.bfcall(), *table_row, &result_writer.NewValue()); |
384 | | |
385 | 1.71M | case PgsqlExpressionPB::ExprCase::kTscall: |
386 | 1.71M | return EvalTSCall(ql_expr.tscall(), *table_row, &result_writer.NewValue(), schema); |
387 | | |
388 | 33 | case PgsqlExpressionPB::ExprCase::kCondition: |
389 | 33 | return EvalCondition(ql_expr.condition(), *table_row, &result_writer.NewValue()); |
390 | | |
391 | 0 | case PgsqlExpressionPB::ExprCase::kBocall: FALLTHROUGH_INTENDED; |
392 | 0 | case PgsqlExpressionPB::ExprCase::kBindId: FALLTHROUGH_INTENDED; |
393 | 0 | case PgsqlExpressionPB::ExprCase::kAliasId: FALLTHROUGH_INTENDED; |
394 | 0 | case PgsqlExpressionPB::ExprCase::EXPR_NOT_SET: |
395 | 0 | result_writer.SetNull(); |
396 | 240M | } |
397 | 10.2M | return Status::OK(); |
398 | 240M | } |
399 | | |
400 | | //-------------------------------------------------------------------------------------------------- |
401 | | |
402 | | CHECKED_STATUS QLExprExecutor::ReadExprValue(const PgsqlExpressionPB& ql_expr, |
403 | | const QLTableRow& table_row, |
404 | 0 | QLExprResultWriter result_writer) { |
405 | 0 | if (ql_expr.expr_case() == PgsqlExpressionPB::ExprCase::kTscall) { |
406 | 0 | return ReadTSCallValue(ql_expr.tscall(), table_row, result_writer); |
407 | 0 | } else { |
408 | 0 | return EvalExpr(ql_expr, table_row, result_writer); |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | | //-------------------------------------------------------------------------------------------------- |
413 | | |
414 | | CHECKED_STATUS QLExprExecutor::EvalColumnRef(ColumnIdRep col_id, |
415 | | const QLTableRow* table_row, |
416 | 0 | QLExprResultWriter result_writer) { |
417 | 0 | if (table_row == nullptr) { |
418 | 0 | result_writer.SetNull(); |
419 | 0 | } else { |
420 | 0 | RETURN_NOT_OK(table_row->ReadColumn(col_id, result_writer)); |
421 | 0 | } |
422 | 0 | return Status::OK(); |
423 | 0 | } |
424 | | |
425 | | //-------------------------------------------------------------------------------------------------- |
426 | | |
427 | | CHECKED_STATUS QLExprExecutor::EvalBFCall(const PgsqlBCallPB& bfcall, |
428 | | const QLTableRow& table_row, |
429 | 0 | QLValue *result) { |
430 | | // TODO(neil) |
431 | | // - Use TSOpode for collection expression if only TabletServer can execute. |
432 | | // OR |
433 | | // - Introduce BuiltinOperator in addition to builtin function. Use builtin operators for all |
434 | | // special operations including collection operations. That way, we don't need special cases. |
435 | | |
436 | | // First, evaluate the arguments. |
437 | 0 | vector<QLValue> args(bfcall.operands().size()); |
438 | 0 | int arg_index = 0; |
439 | 0 | QLExprResult temp; |
440 | 0 | for (auto operand : bfcall.operands()) { |
441 | 0 | RETURN_NOT_OK(EvalExpr(operand, &table_row, temp.Writer())); |
442 | 0 | temp.MoveTo(args[arg_index++].mutable_value()); |
443 | 0 | } |
444 | | |
445 | | // Now, execute the builtin call associated with the given opcode. |
446 | 0 | return PgsqlBfunc::Exec(static_cast<bfpg::BFOpcode>(bfcall.opcode()), &args, result); |
447 | 0 | } |
448 | | |
449 | | //-------------------------------------------------------------------------------------------------- |
450 | | |
451 | | CHECKED_STATUS QLExprExecutor::EvalTSCall(const PgsqlBCallPB& ql_expr, |
452 | | const QLTableRow& table_row, |
453 | | QLValue *result, |
454 | 0 | const Schema *schema) { |
455 | 0 | result->SetNull(); |
456 | 0 | return STATUS(RuntimeError, "Only tablet server can execute this operator"); |
457 | 0 | } |
458 | | |
459 | | CHECKED_STATUS QLExprExecutor::ReadTSCallValue(const PgsqlBCallPB& ql_expr, |
460 | | const QLTableRow& table_row, |
461 | 0 | QLExprResultWriter result_writer) { |
462 | 0 | result_writer.SetNull(); |
463 | 0 | return STATUS(RuntimeError, "Only tablet server can execute this operator"); |
464 | 0 | } |
465 | | |
466 | | //-------------------------------------------------------------------------------------------------- |
467 | | |
468 | | CHECKED_STATUS QLExprExecutor::EvalCondition(const PgsqlConditionPB& condition, |
469 | | const QLTableRow& table_row, |
470 | 0 | bool* result) { |
471 | 0 | QLValue result_pb; |
472 | 0 | RETURN_NOT_OK(EvalCondition(condition, table_row, &result_pb)); |
473 | 0 | *result = result_pb.bool_value(); |
474 | 0 | return Status::OK(); |
475 | 0 | } |
476 | | |
477 | | CHECKED_STATUS QLExprExecutor::EvalCondition(const PgsqlConditionPB& condition, |
478 | | const QLTableRow& table_row, |
479 | 95 | QLValue *result) { |
480 | 95 | #define QL_EVALUATE_RELATIONAL_OP(op) \ |
481 | 62 | result->set_bool_value(VERIFY_RESULT(EvalRelationalOp(this, operands, table_row, op))); \ |
482 | 62 | return Status::OK(); |
483 | | |
484 | 95 | QLExprResult temp; |
485 | 95 | const auto& operands = condition.operands(); |
486 | 95 | switch (condition.op()) { |
487 | 0 | case QL_OP_NOT: { |
488 | 0 | CHECK_EQ(operands.size(), 1); |
489 | 0 | CHECK_EQ(operands.Get(0).expr_case(), PgsqlExpressionPB::ExprCase::kCondition); |
490 | 0 | QLValue sub_result; |
491 | 0 | RETURN_NOT_OK(EvalCondition(operands.Get(0).condition(), table_row, &sub_result)); |
492 | 0 | result->set_bool_value(!sub_result.bool_value()); |
493 | 0 | return Status::OK(); |
494 | 0 | } |
495 | |
|
496 | 0 | case QL_OP_IS_NULL: |
497 | 0 | CHECK_EQ(operands.size(), 1); |
498 | 0 | RETURN_NOT_OK(EvalExpr(operands.Get(0), table_row, temp.Writer())); |
499 | 0 | result->set_bool_value(IsNull(temp.Value())); |
500 | 0 | return Status::OK(); |
501 | |
|
502 | 0 | case QL_OP_IS_NOT_NULL: |
503 | 0 | CHECK_EQ(operands.size(), 1); |
504 | 0 | RETURN_NOT_OK(EvalExpr(operands.Get(0), table_row, temp.Writer())); |
505 | 0 | result->set_bool_value(!IsNull(temp.Value())); |
506 | 0 | return Status::OK(); |
507 | |
|
508 | 0 | case QL_OP_IS_TRUE: |
509 | 0 | result->set_bool_value(VERIFY_RESULT(Is<true>(this, operands, table_row))); |
510 | 0 | return Status::OK(); |
511 | |
|
512 | 0 | case QL_OP_IS_FALSE: { |
513 | 0 | result->set_bool_value(VERIFY_RESULT(Is<false>(this, operands, table_row))); |
514 | 0 | return Status::OK(); |
515 | 0 | } |
516 | |
|
517 | 62 | case QL_OP_EQUAL: |
518 | 62 | QL_EVALUATE_RELATIONAL_OP(std::equal_to<>()); |
519 | |
|
520 | 0 | case QL_OP_LESS_THAN: |
521 | 0 | QL_EVALUATE_RELATIONAL_OP(std::less<>()); |
522 | |
|
523 | 0 | case QL_OP_LESS_THAN_EQUAL: |
524 | 0 | QL_EVALUATE_RELATIONAL_OP(std::less_equal<>()); |
525 | |
|
526 | 0 | case QL_OP_GREATER_THAN: |
527 | 0 | QL_EVALUATE_RELATIONAL_OP(std::greater<>()); |
528 | |
|
529 | 0 | case QL_OP_GREATER_THAN_EQUAL: |
530 | 0 | QL_EVALUATE_RELATIONAL_OP(std::greater_equal<>()); |
531 | |
|
532 | 0 | case QL_OP_NOT_EQUAL: |
533 | 0 | QL_EVALUATE_RELATIONAL_OP(std::not_equal_to<>()); |
534 | |
|
535 | 31 | case QL_OP_AND: |
536 | 31 | CHECK_GT(operands.size(), 0); |
537 | 62 | for (const auto &operand : operands) { |
538 | 62 | CHECK_EQ(operand.expr_case(), PgsqlExpressionPB::ExprCase::kCondition); |
539 | 62 | RETURN_NOT_OK(EvalCondition(operand.condition(), table_row, result)); |
540 | 62 | if (!result->bool_value()) { |
541 | 0 | break; |
542 | 0 | } |
543 | 62 | } |
544 | 31 | return Status::OK(); |
545 | | |
546 | 0 | case QL_OP_OR: |
547 | 0 | CHECK_GT(operands.size(), 0); |
548 | 0 | for (const auto &operand : operands) { |
549 | 0 | CHECK_EQ(operand.expr_case(), PgsqlExpressionPB::ExprCase::kCondition); |
550 | 0 | RETURN_NOT_OK(EvalCondition(operand.condition(), table_row, result)); |
551 | 0 | if (result->bool_value()) { |
552 | 0 | break; |
553 | 0 | } |
554 | 0 | } |
555 | 0 | return Status::OK(); |
556 | |
|
557 | 0 | case QL_OP_BETWEEN: |
558 | 0 | result->set_bool_value(VERIFY_RESULT(Between(this, operands, table_row))); |
559 | 0 | return Status::OK(); |
560 | |
|
561 | 0 | case QL_OP_NOT_BETWEEN: |
562 | 0 | result->set_bool_value(!VERIFY_RESULT(Between(this, operands, table_row))); |
563 | 0 | return Status::OK(); |
564 | | |
565 | | // When a row exists, the primary key columns are always populated in the row (value-map) by |
566 | | // DocRowwiseIterator and only when it exists. Therefore, the row exists if and only if |
567 | | // the row (value-map) is not empty. |
568 | 2 | case QL_OP_EXISTS: |
569 | 2 | result->set_bool_value(!table_row.IsEmpty()); |
570 | 2 | return Status::OK(); |
571 | |
|
572 | 0 | case QL_OP_NOT_EXISTS: |
573 | 0 | result->set_bool_value(table_row.IsEmpty()); |
574 | 0 | return Status::OK(); |
575 | |
|
576 | 0 | case QL_OP_IN: |
577 | 0 | CHECK_EQ(operands.size(), 2); |
578 | 0 | result->set_bool_value(VERIFY_RESULT(In(this, operands, table_row))); |
579 | 0 | break; |
580 | |
|
581 | 0 | case QL_OP_NOT_IN: |
582 | 0 | CHECK_EQ(operands.size(), 2); |
583 | 0 | result->set_bool_value(!VERIFY_RESULT(In(this, operands, table_row))); |
584 | 0 | break; |
585 | |
|
586 | 0 | case QL_OP_LIKE: FALLTHROUGH_INTENDED; |
587 | 0 | case QL_OP_NOT_LIKE: |
588 | 0 | LOG(ERROR) << "Internal error: illegal or unknown operator " << condition.op(); |
589 | 0 | break; |
590 | |
|
591 | 0 | case QL_OP_NOOP: |
592 | 0 | break; |
593 | 0 | } |
594 | | |
595 | 0 | result->SetNull(); |
596 | 0 | return STATUS(RuntimeError, "Internal error: illegal or unknown operator"); |
597 | |
|
598 | 0 | #undef QL_EVALUATE_RELATIONAL_OP |
599 | 0 | #undef QL_EVALUATE_BETWEEN |
600 | 0 | } |
601 | | |
602 | | //-------------------------------------------------------------------------------------------------- |
603 | | |
604 | 6.27M | const QLTableRow& QLTableRow::empty_row() { |
605 | 6.27M | static QLTableRow empty_row; |
606 | 6.27M | return empty_row; |
607 | 6.27M | } |
608 | | |
609 | 77.3k | size_t QLTableRow::ColumnCount() const { |
610 | 77.3k | size_t result = 0; |
611 | 1.30M | for (auto i : assigned_) { |
612 | 1.30M | result += i; |
613 | 1.30M | } |
614 | 77.3k | return result; |
615 | 77.3k | } |
616 | | |
617 | 32.4M | void QLTableRow::Clear() { |
618 | 32.4M | if (num_assigned_ == 0) { |
619 | 6.55M | return; |
620 | 6.55M | } |
621 | | |
622 | 25.9M | memset(assigned_.data(), 0, assigned_.size()); |
623 | 25.9M | num_assigned_ = 0; |
624 | 25.9M | } |
625 | | |
626 | 265M | size_t QLTableRow::ColumnIndex(ColumnIdRep col_id) const { |
627 | 265M | if (col_id < kFirstNonPreallocatedColumnId && col_id >= kFirstColumnIdRep) { |
628 | 162M | return col_id - kFirstColumnIdRep; |
629 | 162M | } |
630 | 102M | const auto& col_iter = column_id_to_index_.find(col_id); |
631 | 102M | if (col_iter == column_id_to_index_.end()) { |
632 | 4 | return kInvalidIndex; |
633 | 4 | } |
634 | | |
635 | 102M | return col_iter->second; |
636 | 102M | } |
637 | | |
638 | 265M | const QLTableColumn* QLTableRow::FindColumn(ColumnIdRep col_id) const { |
639 | 265M | size_t index = ColumnIndex(col_id); |
640 | 265M | if (index == kInvalidIndex || index >= assigned_.size() || !assigned_[index]) { |
641 | 15.5k | return nullptr; |
642 | 15.5k | } |
643 | | |
644 | 265M | return &values_[index]; |
645 | 265M | } |
646 | | |
647 | 249M | const QLValuePB* QLTableRow::GetColumn(ColumnIdRep col_id) const { |
648 | 249M | const auto* column = FindColumn(col_id); |
649 | 249M | return column ? &column->value : nullptr; |
650 | 249M | } |
651 | | |
652 | 249M | CHECKED_STATUS QLTableRow::ReadColumn(ColumnIdRep col_id, QLExprResultWriter result_writer) const { |
653 | 249M | auto value = GetColumn(col_id); |
654 | 249M | if (value == nullptr) { |
655 | 2.92k | result_writer.SetNull(); |
656 | 2.92k | return Status::OK(); |
657 | 2.92k | } |
658 | | |
659 | 249M | result_writer.SetExisting(value); |
660 | 249M | return Status::OK(); |
661 | 249M | } |
662 | | |
663 | | CHECKED_STATUS QLTableRow::ReadSubscriptedColumn(const QLSubscriptedColPB& subcol, |
664 | | const QLValuePB& index_arg, |
665 | 193 | QLExprResultWriter result_writer) const { |
666 | 193 | const auto* value = GetColumn(subcol.column_id()); |
667 | 193 | if (!value) { |
668 | | // Does not exist. |
669 | 0 | result_writer.SetNull(); |
670 | 0 | return Status::OK(); |
671 | 0 | } |
672 | | |
673 | 193 | if (value->has_map_value()) { |
674 | | // map['key'] |
675 | 147 | auto& map = value->map_value(); |
676 | 152 | for (int i = 0; i < map.keys_size(); i++) { |
677 | 147 | if (map.keys(i) == index_arg) { |
678 | 142 | result_writer.SetExisting(&map.values(i)); |
679 | 142 | return Status::OK(); |
680 | 142 | } |
681 | 147 | } |
682 | 46 | } else if (value->has_list_value()) { |
683 | | // list[index] |
684 | 24 | auto& list = value->list_value(); |
685 | 24 | if (index_arg.has_int32_value()) { |
686 | 24 | int list_index = index_arg.int32_value(); |
687 | 24 | if (list_index >= 0 && list_index < list.elems_size()) { |
688 | 23 | result_writer.SetExisting(&list.elems(list_index)); |
689 | 23 | return Status::OK(); |
690 | 23 | } |
691 | 28 | } |
692 | 24 | } |
693 | | |
694 | 28 | result_writer.SetNull(); |
695 | 28 | return Status::OK(); |
696 | 28 | } |
697 | | |
698 | 6.75M | Result<const QLTableColumn&> QLTableRow::Column(ColumnIdRep col_id) const { |
699 | 6.75M | const auto* column = FindColumn(col_id); |
700 | 6.75M | if (column == nullptr) { |
701 | | // Does not exist. |
702 | 0 | return STATUS(InternalError, "Column unexpectedly not found in cache"); |
703 | 0 | } |
704 | | |
705 | 6.75M | return *column; |
706 | 6.75M | } |
707 | | |
708 | 41 | CHECKED_STATUS QLTableRow::GetTTL(ColumnIdRep col_id, int64_t *ttl_seconds) const { |
709 | 41 | *ttl_seconds = VERIFY_RESULT(Column(col_id)).get().ttl_seconds; |
710 | 41 | return Status::OK(); |
711 | 41 | } |
712 | | |
713 | 5.82k | CHECKED_STATUS QLTableRow::GetWriteTime(ColumnIdRep col_id, int64_t *write_time) const { |
714 | 5.82k | const QLTableColumn& column = VERIFY_RESULT(Column(col_id)); |
715 | 0 | DCHECK_NE(QLTableColumn::kUninitializedWriteTime, column.write_time) << "Column id: " << col_id; |
716 | 5.82k | *write_time = column.write_time; |
717 | 5.82k | return Status::OK(); |
718 | 5.82k | } |
719 | | |
720 | 6.77M | CHECKED_STATUS QLTableRow::GetValue(ColumnIdRep col_id, QLValue *column) const { |
721 | 6.77M | *column = VERIFY_RESULT(Column(col_id)).get().value; |
722 | 6.77M | return Status::OK(); |
723 | 6.77M | } |
724 | | |
725 | 6.76M | CHECKED_STATUS QLTableRow::GetValue(const ColumnId& col, QLValue *column) const { |
726 | 6.76M | return GetValue(col.rep(), column); |
727 | 6.76M | } |
728 | | |
729 | 8.95M | boost::optional<const QLValuePB&> QLTableRow::GetValue(ColumnIdRep col_id) const { |
730 | 8.95M | const auto* column = FindColumn(col_id); |
731 | 8.95M | if (column) { |
732 | 8.95M | return column->value; |
733 | 8.95M | } |
734 | 3.44k | return boost::none; |
735 | 3.44k | } |
736 | | |
737 | 337 | bool QLTableRow::IsColumnSpecified(ColumnIdRep col_id) const { |
738 | 337 | size_t index = ColumnIndex(col_id); |
739 | 337 | if (index == kInvalidIndex) { |
740 | 0 | LOG(DFATAL) << "Checking whether unknown column is specified: " << col_id; |
741 | 0 | return false; |
742 | 0 | } |
743 | 337 | return assigned_[index]; |
744 | 337 | } |
745 | | |
746 | 39 | void QLTableRow::MarkTombstoned(ColumnIdRep col_id) { |
747 | 39 | AllocColumn(col_id).value.Clear(); |
748 | 39 | } |
749 | | |
750 | 40.2k | bool QLTableRow::MatchColumn(ColumnIdRep col_id, const QLTableRow& source) const { |
751 | 40.2k | const auto* this_column = FindColumn(col_id); |
752 | 40.2k | const auto* source_column = source.FindColumn(col_id); |
753 | 40.2k | if (this_column && source_column) { |
754 | 30.8k | return this_column->value == source_column->value; |
755 | 30.8k | } |
756 | 9.46k | return !this_column && !source_column; |
757 | 9.46k | } |
758 | | |
759 | 27.2M | QLTableColumn& QLTableRow::AppendColumn() { |
760 | 27.2M | values_.emplace_back(); |
761 | 27.2M | assigned_.push_back(true); |
762 | 27.2M | ++num_assigned_; |
763 | 27.2M | return values_.back(); |
764 | 27.2M | } |
765 | | |
766 | 292M | QLTableColumn& QLTableRow::AllocColumn(ColumnIdRep col_id) { |
767 | 292M | size_t index = col_id; |
768 | 292M | if (index < kFirstNonPreallocatedColumnId && index >= kFirstColumnIdRep) { |
769 | 188M | index -= kFirstColumnIdRep; |
770 | | // We are in directly mapped part. Ensure that vector is big enough. |
771 | 188M | if (values_.size() <= index) { |
772 | | // We don't need reserve here, because no allocation would take place. |
773 | 23.4M | if (values_.size() < index) { |
774 | 45.1k | values_.resize(index); |
775 | 45.1k | assigned_.resize(index); |
776 | 45.1k | } |
777 | | // This column was not yet allocated, so allocate it. Also vector has `col_id` size, so |
778 | | // new column will be added at `col_id` position. |
779 | 23.4M | return AppendColumn(); |
780 | 23.4M | } |
781 | 103M | } else { |
782 | | // We are in part that is mapped using `column_id_to_index_`, so need to allocate at least |
783 | | // part that is mapped directly, to avoid index overlapping. |
784 | 103M | if (values_.size() < kPreallocatedSize) { |
785 | 1.58k | values_.resize(kPreallocatedSize); |
786 | 1.58k | assigned_.resize(kPreallocatedSize); |
787 | 1.58k | } |
788 | 103M | auto iterator_and_flag = column_id_to_index_.emplace(col_id, values_.size()); |
789 | 103M | if (iterator_and_flag.second) { |
790 | 3.82M | return AppendColumn(); |
791 | 3.82M | } |
792 | 99.5M | index = iterator_and_flag.first->second; |
793 | 99.5M | } |
794 | | |
795 | 264M | if (!assigned_[index]) { |
796 | 249M | assigned_[index] = true; |
797 | 249M | ++num_assigned_; |
798 | 249M | } |
799 | 264M | return values_[index]; |
800 | 292M | } |
801 | | |
802 | 21.4M | QLTableColumn& QLTableRow::AllocColumn(ColumnIdRep col_id, const QLValue& ql_value) { |
803 | 21.4M | return AllocColumn(col_id, ql_value.value()); |
804 | 21.4M | } |
805 | | |
806 | 26.5M | QLTableColumn& QLTableRow::AllocColumn(ColumnIdRep col_id, const QLValuePB& ql_value) { |
807 | 26.5M | QLTableColumn& result = AllocColumn(col_id); |
808 | 26.5M | result.value = ql_value; |
809 | 26.5M | return result; |
810 | 26.5M | } |
811 | | |
812 | 77.3k | QLTableColumn& QLTableRow::AllocColumn(ColumnIdRep col_id, QLValuePB&& ql_value) { |
813 | 77.3k | QLTableColumn& result = AllocColumn(col_id); |
814 | 77.3k | result.value = std::move(ql_value); |
815 | 77.3k | return result; |
816 | 77.3k | } |
817 | | |
818 | 419 | void QLTableRow::CopyColumn(ColumnIdRep col_id, const QLTableRow& source) { |
819 | 419 | const auto* value = source.FindColumn(col_id); |
820 | 419 | if (value) { |
821 | 419 | AllocColumn(col_id) = *value; |
822 | 419 | return; |
823 | 419 | } |
824 | | |
825 | 0 | auto index = ColumnIndex(col_id); |
826 | 0 | if (index == kInvalidIndex) { |
827 | 0 | return; |
828 | 0 | } |
829 | 0 | if (assigned_[index]) { |
830 | 0 | assigned_[index] = false; |
831 | 0 | --num_assigned_; |
832 | 0 | } |
833 | 0 | } |
834 | | |
835 | 1 | std::string QLTableRow::ToString() const { |
836 | 1 | std::string ret("{ "); |
837 | | |
838 | 2 | for (size_t i = 0; i != kPreallocatedSize; ++i) { |
839 | 2 | if (i >= values_.size()) { |
840 | 1 | break; |
841 | 1 | } |
842 | 1 | if (!assigned_[i]) { |
843 | 0 | continue; |
844 | 0 | } |
845 | 1 | ret.append(Format("$0 => $1 ", i + kFirstColumnIdRep, values_[i])); |
846 | 1 | } |
847 | | |
848 | 0 | for (auto p : column_id_to_index_) { |
849 | 0 | if (!assigned_[p.second]) { |
850 | 0 | continue; |
851 | 0 | } |
852 | | |
853 | 0 | ret.append(Format("$0 => $1 ", p.first, values_[p.second])); |
854 | 0 | } |
855 | | |
856 | 1 | ret.append("}"); |
857 | 1 | return ret; |
858 | 1 | } |
859 | | |
860 | 5.16k | std::string QLTableRow::ToString(const Schema& schema) const { |
861 | 5.16k | std::string ret; |
862 | 5.16k | ret.append("{ "); |
863 | | |
864 | 20.6k | for (size_t col_idx = 0; col_idx < schema.num_columns(); col_idx++) { |
865 | 15.4k | const auto* value = GetColumn(schema.column_id(col_idx)); |
866 | 15.4k | if (value && value->value_case() != QLValuePB::VALUE_NOT_SET) { |
867 | 15.1k | ret += value->ShortDebugString(); |
868 | 351 | } else { |
869 | 351 | ret += "null"; |
870 | 351 | } |
871 | 15.4k | ret += ' '; |
872 | 15.4k | } |
873 | 5.16k | ret.append("}"); |
874 | 5.16k | return ret; |
875 | 5.16k | } |
876 | | |
877 | 17.8k | void QLExprResult::MoveToJsonb(common::Jsonb* out) { |
878 | 17.8k | if (existing_value_) { |
879 | 17.8k | out->Assign(existing_value_->jsonb_value()); |
880 | 17.8k | existing_value_ = nullptr; |
881 | 0 | } else { |
882 | 0 | out->Assign(std::move(*value_.mutable_value()->mutable_jsonb_value())); |
883 | 0 | } |
884 | 17.8k | } |
885 | | |
886 | 282M | const QLValuePB& QLExprResult::Value() const { |
887 | 282M | if (existing_value_) { |
888 | 267M | return *existing_value_; |
889 | 267M | } |
890 | | |
891 | 15.2M | return value_.value(); |
892 | 15.2M | } |
893 | | |
894 | 18.0k | bool QLExprResult::IsNull() const { |
895 | 18.0k | if (existing_value_) { |
896 | 17.9k | return yb::IsNull(*existing_value_); |
897 | 17.9k | } |
898 | | |
899 | 89 | return value_.IsNull(); |
900 | 89 | } |
901 | | |
902 | 4.94k | void QLExprResult::MoveTo(QLValuePB* out) { |
903 | 4.94k | if (existing_value_) { |
904 | 537 | *out = *existing_value_; |
905 | 537 | existing_value_ = nullptr; |
906 | 4.41k | } else { |
907 | 4.41k | value_.mutable_value()->Swap(out); |
908 | 4.41k | } |
909 | 4.94k | } |
910 | | |
911 | 22 | QLValue& QLExprResult::ForceNewValue() { |
912 | 22 | if (existing_value_) { |
913 | 11 | value_ = *existing_value_; |
914 | 11 | existing_value_ = nullptr; |
915 | 11 | } |
916 | | |
917 | 22 | return value_; |
918 | 22 | } |
919 | | |
920 | 282M | QLExprResultWriter QLExprResult::Writer() { |
921 | 282M | return QLExprResultWriter(this); |
922 | 282M | } |
923 | | |
924 | 3.17k | void QLExprResultWriter::SetNull() { |
925 | 3.17k | result_->value_.SetNull(); |
926 | 3.17k | } |
927 | | |
928 | 265M | void QLExprResultWriter::SetExisting(const QLValuePB* existing_value) { |
929 | 265M | result_->existing_value_ = existing_value; |
930 | 265M | } |
931 | | |
932 | 17.0M | QLValue& QLExprResultWriter::NewValue() { |
933 | 17.0M | return result_->value_; |
934 | 17.0M | } |
935 | | |
936 | 1 | std::string QLTableColumn::ToString() const { |
937 | 1 | return Format("{ value: $0 ttl_seconds: $1 write_time: $2 }", value, ttl_seconds, |
938 | 1 | write_time == kUninitializedWriteTime ? "kUninitializedWriteTime": |
939 | 0 | std::to_string(write_time)); |
940 | 1 | } |
941 | | |
942 | | } // namespace yb |