/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 | 6.73M | 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 | 6.73M | if (ql_expr.has_tscall()) { |
26 | 48 | return static_cast<bfql::TSOpcode>(ql_expr.tscall().opcode()); |
27 | 48 | } |
28 | 6.73M | return bfql::TSOpcode::kScalarInsert; |
29 | 6.73M | } |
30 | | |
31 | | //-------------------------------------------------------------------------------------------------- |
32 | | |
33 | | CHECKED_STATUS QLExprExecutor::EvalExpr(const QLExpressionPB& ql_expr, |
34 | | const QLTableRow& table_row, |
35 | | QLExprResultWriter result_writer, |
36 | 54.3M | const Schema *schema) { |
37 | 54.3M | switch (ql_expr.expr_case()) { |
38 | 7.86M | case QLExpressionPB::ExprCase::kValue: |
39 | 7.86M | result_writer.SetExisting(&ql_expr.value()); |
40 | 7.86M | break; |
41 | | |
42 | 46.3M | case QLExpressionPB::ExprCase::kColumnId: |
43 | 46.3M | RETURN_NOT_OK(table_row.ReadColumn(ql_expr.column_id(), result_writer)); |
44 | 46.3M | break; |
45 | | |
46 | 46.3M | case QLExpressionPB::ExprCase::kJsonColumn: { |
47 | 18.2k | QLExprResult temp; |
48 | 18.2k | const QLJsonColumnOperationsPB& json_ops = ql_expr.json_column(); |
49 | 18.2k | RETURN_NOT_OK(table_row.ReadColumn(json_ops.column_id(), temp.Writer())); |
50 | 18.2k | if (temp.IsNull()) { |
51 | 217 | result_writer.SetNull(); |
52 | 18.0k | } else { |
53 | 18.0k | common::Jsonb jsonb; |
54 | 18.0k | temp.MoveToJsonb(&jsonb); |
55 | 18.0k | RETURN_NOT_OK(jsonb.ApplyJsonbOperators(json_ops, &result_writer.NewValue())); |
56 | 18.0k | } |
57 | 18.2k | break; |
58 | 18.2k | } |
59 | | |
60 | 18.2k | case QLExpressionPB::ExprCase::kSubscriptedCol: |
61 | 194 | if (table_row.IsEmpty()) { |
62 | 0 | result_writer.SetNull(); |
63 | 194 | } else { |
64 | 194 | QLExprResult index_arg; |
65 | 194 | const QLSubscriptedColPB& subcol = ql_expr.subscripted_col(); |
66 | 194 | RETURN_NOT_OK(EvalExpr(subcol.subscript_args(0), table_row, index_arg.Writer())); |
67 | 194 | RETURN_NOT_OK(table_row.ReadSubscriptedColumn(subcol, index_arg.Value(), result_writer)); |
68 | 194 | } |
69 | 194 | break; |
70 | | |
71 | 728 | case QLExpressionPB::ExprCase::kBfcall: |
72 | 728 | return EvalBFCall(ql_expr.bfcall(), table_row, &result_writer.NewValue()); |
73 | | |
74 | 20.7k | case QLExpressionPB::ExprCase::kTscall: |
75 | 20.7k | 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 | 54.3M | } |
85 | 54.2M | return Status::OK(); |
86 | 54.3M | } |
87 | | |
88 | | //-------------------------------------------------------------------------------------------------- |
89 | | |
90 | | CHECKED_STATUS QLExprExecutor::EvalExpr(QLExpressionPB* ql_expr, |
91 | | const QLTableRow& table_row, |
92 | 11.2M | const Schema *schema) { |
93 | 11.2M | 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 | 11.2M | return Status::OK(); |
99 | 11.2M | } |
100 | | |
101 | | CHECKED_STATUS QLExprExecutor::EvalExpr(const PgsqlExpressionPB& ql_expr, |
102 | | const QLTableRow& table_row, |
103 | | QLExprResultWriter result_writer, |
104 | 707M | const Schema *schema) { |
105 | 707M | return EvalExpr(ql_expr, &table_row, result_writer, schema); |
106 | 707M | } |
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 | 670k | bool* result) { |
176 | 670k | QLValue result_pb; |
177 | 670k | RETURN_NOT_OK(EvalCondition(condition, table_row, &result_pb)); |
178 | 670k | *result = result_pb.bool_value(); |
179 | 670k | return Status::OK(); |
180 | 670k | } |
181 | | |
182 | | template <class Operands> |
183 | | Result<bool> In( |
184 | 933 | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row) { |
185 | 933 | QLExprResult left, right; |
186 | 933 | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); |
187 | | |
188 | 2.38k | for (const QLValuePB& elem : right.Value().list_value().elems())933 { |
189 | 2.38k | if (!Comparable(elem, left.Value())) { |
190 | 0 | return STATUS(RuntimeError, "values not comparable"); |
191 | 0 | } |
192 | 2.38k | if (elem == left.Value()) { |
193 | 784 | return true; |
194 | 784 | } |
195 | 2.38k | } |
196 | | |
197 | 149 | return false; |
198 | 933 | } yb::Result<bool> yb::In<google::protobuf::RepeatedPtrField<yb::QLExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&) Line | Count | Source | 184 | 933 | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row) { | 185 | 933 | QLExprResult left, right; | 186 | 933 | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 187 | | | 188 | 2.38k | for (const QLValuePB& elem : right.Value().list_value().elems())933 { | 189 | 2.38k | if (!Comparable(elem, left.Value())) { | 190 | 0 | return STATUS(RuntimeError, "values not comparable"); | 191 | 0 | } | 192 | 2.38k | if (elem == left.Value()) { | 193 | 784 | return true; | 194 | 784 | } | 195 | 2.38k | } | 196 | | | 197 | 149 | return false; | 198 | 933 | } |
Unexecuted instantiation: yb::Result<bool> yb::In<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&) |
199 | | |
200 | | template <class Operands, class Op> |
201 | | Result<bool> EvalRelationalOp( |
202 | 1.12M | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { |
203 | 1.12M | QLExprResult left, right; |
204 | 1.12M | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); |
205 | 1.12M | if (!Comparable(left.Value(), right.Value())) { |
206 | 0 | return STATUS(RuntimeError, "values not comparable"); |
207 | 0 | } |
208 | 1.12M | return op(left.Value(), right.Value()); |
209 | 1.12M | } yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::QLExpressionPB>, std::__1::equal_to<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&, std::__1::equal_to<void> const&) Line | Count | Source | 202 | 184k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 184k | QLExprResult left, right; | 204 | 184k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 184k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 184k | return op(left.Value(), right.Value()); | 209 | 184k | } |
yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::QLExpressionPB>, std::__1::less<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&, std::__1::less<void> const&) Line | Count | Source | 202 | 434k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 434k | QLExprResult left, right; | 204 | 434k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 434k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 434k | return op(left.Value(), right.Value()); | 209 | 434k | } |
yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::QLExpressionPB>, std::__1::less_equal<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&, std::__1::less_equal<void> const&) Line | Count | Source | 202 | 28.1k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 28.1k | QLExprResult left, right; | 204 | 28.1k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 28.1k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 28.1k | return op(left.Value(), right.Value()); | 209 | 28.1k | } |
yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::QLExpressionPB>, std::__1::greater<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&, std::__1::greater<void> const&) Line | Count | Source | 202 | 444k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 444k | QLExprResult left, right; | 204 | 444k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 444k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 444k | return op(left.Value(), right.Value()); | 209 | 444k | } |
yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::QLExpressionPB>, std::__1::greater_equal<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&, std::__1::greater_equal<void> const&) Line | Count | Source | 202 | 29.3k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 29.3k | QLExprResult left, right; | 204 | 29.3k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 29.3k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 29.3k | return op(left.Value(), right.Value()); | 209 | 29.3k | } |
yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::QLExpressionPB>, std::__1::not_equal_to<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&, std::__1::not_equal_to<void> const&) Line | Count | Source | 202 | 2.01k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 2.01k | QLExprResult left, right; | 204 | 2.01k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 2.01k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 2.01k | return op(left.Value(), right.Value()); | 209 | 2.01k | } |
yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB>, std::__1::equal_to<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&, std::__1::equal_to<void> const&) Line | Count | Source | 202 | 5.90k | QLExprExecutor* executor, const Operands& operands, const QLTableRow& table_row, const Op& op) { | 203 | 5.90k | QLExprResult left, right; | 204 | 5.90k | RETURN_NOT_OK(EvalOperands(executor, operands, table_row, left.Writer(), right.Writer())); | 205 | 5.90k | if (!Comparable(left.Value(), right.Value())) { | 206 | 0 | return STATUS(RuntimeError, "values not comparable"); | 207 | 0 | } | 208 | 5.90k | return op(left.Value(), right.Value()); | 209 | 5.90k | } |
Unexecuted instantiation: yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB>, std::__1::less<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&, std::__1::less<void> const&) Unexecuted instantiation: yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB>, std::__1::less_equal<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&, std::__1::less_equal<void> const&) Unexecuted instantiation: yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB>, std::__1::greater<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&, std::__1::greater<void> const&) Unexecuted instantiation: yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB>, std::__1::greater_equal<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&, std::__1::greater_equal<void> const&) Unexecuted instantiation: yb::Result<bool> yb::EvalRelationalOp<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB>, std::__1::not_equal_to<void> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&, std::__1::not_equal_to<void> const&) |
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: yb::Result<bool> yb::Is<true, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&) Unexecuted instantiation: yb::Result<bool> yb::Is<false, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&) Unexecuted instantiation: yb::Result<bool> yb::Is<true, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&) Unexecuted instantiation: yb::Result<bool> yb::Is<false, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&) |
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: yb::Result<bool> yb::Between<google::protobuf::RepeatedPtrField<yb::QLExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::QLExpressionPB> const&, yb::QLTableRow const&) Unexecuted instantiation: yb::Result<bool> yb::Between<google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> >(yb::QLExprExecutor*, google::protobuf::RepeatedPtrField<yb::PgsqlExpressionPB> const&, yb::QLTableRow const&) |
234 | | |
235 | | CHECKED_STATUS QLExprExecutor::EvalCondition(const QLConditionPB& condition, |
236 | | const QLTableRow& table_row, |
237 | 1.73M | QLValue *result) { |
238 | 1.73M | #define QL_EVALUATE_RELATIONAL_OP(op) \ |
239 | 1.73M | result->set_bool_value(1.12M VERIFY_RESULT1.12M (EvalRelationalOp(this, operands, table_row, op))); \ |
240 | 1.12M | return Status::OK(); |
241 | | |
242 | 1.73M | QLExprResult temp; |
243 | 1.73M | const auto& operands = condition.operands(); |
244 | 1.73M | 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 | 184k | case QL_OP_EQUAL: |
275 | 184k | QL_EVALUATE_RELATIONAL_OP(std::equal_to<>()); |
276 | |
|
277 | 433k | case QL_OP_LESS_THAN: |
278 | 433k | QL_EVALUATE_RELATIONAL_OP(std::less<>()); |
279 | |
|
280 | 28.1k | case QL_OP_LESS_THAN_EQUAL: |
281 | 28.1k | QL_EVALUATE_RELATIONAL_OP(std::less_equal<>()); |
282 | |
|
283 | 444k | case QL_OP_GREATER_THAN: |
284 | 444k | QL_EVALUATE_RELATIONAL_OP(std::greater<>()); |
285 | |
|
286 | 29.3k | case QL_OP_GREATER_THAN_EQUAL: |
287 | 29.3k | QL_EVALUATE_RELATIONAL_OP(std::greater_equal<>()); |
288 | |
|
289 | 2.01k | case QL_OP_NOT_EQUAL: |
290 | 2.01k | QL_EVALUATE_RELATIONAL_OP(std::not_equal_to<>()); |
291 | |
|
292 | 608k | case QL_OP_AND: |
293 | 608k | CHECK_GT(operands.size(), 0); |
294 | 1.06M | for (const auto &operand : operands) { |
295 | 1.06M | CHECK_EQ(operand.expr_case(), QLExpressionPB::ExprCase::kCondition); |
296 | 1.06M | RETURN_NOT_OK(EvalCondition(operand.condition(), table_row, result)); |
297 | 1.06M | if (!result->bool_value()) { |
298 | 143k | break; |
299 | 143k | } |
300 | 1.06M | } |
301 | 608k | return Status::OK(); |
302 | | |
303 | 209 | case QL_OP_OR: |
304 | 209 | CHECK_GT(operands.size(), 0); |
305 | 333 | for (const auto &operand : operands) { |
306 | 333 | CHECK_EQ(operand.expr_case(), QLExpressionPB::ExprCase::kCondition); |
307 | 333 | RETURN_NOT_OK(EvalCondition(operand.condition(), table_row, result)); |
308 | 333 | if (result->bool_value()) { |
309 | 130 | break; |
310 | 130 | } |
311 | 333 | } |
312 | 209 | 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 | 877 | case QL_OP_IN: |
334 | 877 | CHECK_EQ(operands.size(), 2); |
335 | 877 | result->set_bool_value(VERIFY_RESULT(In(this, operands, table_row))); |
336 | 0 | return Status::OK(); |
337 | | |
338 | 52 | case QL_OP_NOT_IN: |
339 | 52 | CHECK_EQ(operands.size(), 2); |
340 | 52 | result->set_bool_value(!VERIFY_RESULT(In(this, operands, table_row))); |
341 | 0 | 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 | 1.73M | } |
351 | | |
352 | 0 | result->SetNull(); |
353 | 0 | return STATUS(RuntimeError, "Internal error: illegal or unknown operator"); |
354 | | |
355 | 1.73M | #undef QL_EVALUATE_RELATIONAL_OP |
356 | 1.73M | } |
357 | | |
358 | | //-------------------------------------------------------------------------------------------------- |
359 | | |
360 | 49.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 | 49.7M | if (ql_expr.has_tscall()) { |
363 | 33.5k | return static_cast<bfpg::TSOpcode>(ql_expr.tscall().opcode()); |
364 | 33.5k | } |
365 | 49.7M | return bfpg::TSOpcode::kScalarInsert; |
366 | 49.7M | } |
367 | | |
368 | | //-------------------------------------------------------------------------------------------------- |
369 | | |
370 | | CHECKED_STATUS QLExprExecutor::EvalExpr(const PgsqlExpressionPB& ql_expr, |
371 | | const QLTableRow* table_row, |
372 | | QLExprResultWriter result_writer, |
373 | 707M | const Schema *schema) { |
374 | 707M | switch (ql_expr.expr_case()) { |
375 | 47.8M | case PgsqlExpressionPB::ExprCase::kValue: |
376 | 47.8M | result_writer.SetExisting(&ql_expr.value()); |
377 | 47.8M | break; |
378 | | |
379 | 656M | case PgsqlExpressionPB::ExprCase::kColumnId: |
380 | 656M | 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 | 3.14M | case PgsqlExpressionPB::ExprCase::kTscall: |
386 | 3.14M | return EvalTSCall(ql_expr.tscall(), *table_row, &result_writer.NewValue(), schema); |
387 | | |
388 | 2.97k | case PgsqlExpressionPB::ExprCase::kCondition: |
389 | 2.97k | 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 | 707M | } |
397 | 47.8M | return Status::OK(); |
398 | 707M | } |
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 | 8.87k | QLValue *result) { |
480 | 8.87k | #define QL_EVALUATE_RELATIONAL_OP(op) \ |
481 | 8.87k | result->set_bool_value(5.90k VERIFY_RESULT5.90k (EvalRelationalOp(this, operands, table_row, op))); \ |
482 | 5.90k | return Status::OK(); |
483 | | |
484 | 8.87k | QLExprResult temp; |
485 | 8.87k | const auto& operands = condition.operands(); |
486 | 8.87k | 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 | 5.90k | case QL_OP_EQUAL: |
518 | 5.90k | 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 | 2.95k | case QL_OP_AND: |
536 | 2.95k | CHECK_GT(operands.size(), 0); |
537 | 5.90k | for (const auto &operand : operands) { |
538 | 5.90k | CHECK_EQ(operand.expr_case(), PgsqlExpressionPB::ExprCase::kCondition); |
539 | 5.90k | RETURN_NOT_OK(EvalCondition(operand.condition(), table_row, result)); |
540 | 5.90k | if (!result->bool_value()) { |
541 | 0 | break; |
542 | 0 | } |
543 | 5.90k | } |
544 | 2.95k | 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 | 29 | case QL_OP_EXISTS: |
569 | 29 | result->set_bool_value(!table_row.IsEmpty()); |
570 | 29 | 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 | 8.87k | } |
594 | | |
595 | 0 | result->SetNull(); |
596 | 0 | return STATUS(RuntimeError, "Internal error: illegal or unknown operator"); |
597 | | |
598 | 8.87k | #undef QL_EVALUATE_RELATIONAL_OP |
599 | 8.87k | #undef QL_EVALUATE_BETWEEN |
600 | 8.87k | } |
601 | | |
602 | | //-------------------------------------------------------------------------------------------------- |
603 | | |
604 | 11.3M | const QLTableRow& QLTableRow::empty_row() { |
605 | 11.3M | static QLTableRow empty_row; |
606 | 11.3M | return empty_row; |
607 | 11.3M | } |
608 | | |
609 | 125k | size_t QLTableRow::ColumnCount() const { |
610 | 125k | size_t result = 0; |
611 | 1.83M | for (auto i : assigned_) { |
612 | 1.83M | result += i; |
613 | 1.83M | } |
614 | 125k | return result; |
615 | 125k | } |
616 | | |
617 | 75.2M | void QLTableRow::Clear() { |
618 | 75.2M | if (num_assigned_ == 0) { |
619 | 14.5M | return; |
620 | 14.5M | } |
621 | | |
622 | 60.6M | memset(assigned_.data(), 0, assigned_.size()); |
623 | 60.6M | num_assigned_ = 0; |
624 | 60.6M | } |
625 | | |
626 | 720M | size_t QLTableRow::ColumnIndex(ColumnIdRep col_id) const { |
627 | 720M | if (col_id < kFirstNonPreallocatedColumnId && col_id >= kFirstColumnIdRep405M ) { |
628 | 405M | return col_id - kFirstColumnIdRep; |
629 | 405M | } |
630 | 314M | const auto& col_iter = column_id_to_index_.find(col_id); |
631 | 314M | if (col_iter == column_id_to_index_.end()) { |
632 | 4 | return kInvalidIndex; |
633 | 4 | } |
634 | | |
635 | 314M | return col_iter->second; |
636 | 314M | } |
637 | | |
638 | 720M | const QLTableColumn* QLTableRow::FindColumn(ColumnIdRep col_id) const { |
639 | 720M | size_t index = ColumnIndex(col_id); |
640 | 720M | if (index == kInvalidIndex720M || index >= assigned_.size() || !assigned_[index]719M ) { |
641 | 15.6k | return nullptr; |
642 | 15.6k | } |
643 | | |
644 | 720M | return &values_[index]; |
645 | 720M | } |
646 | | |
647 | 662M | const QLValuePB* QLTableRow::GetColumn(ColumnIdRep col_id) const { |
648 | 662M | const auto* column = FindColumn(col_id); |
649 | 662M | return column ? &column->value662M : nullptr174k ; |
650 | 662M | } |
651 | | |
652 | 662M | CHECKED_STATUS QLTableRow::ReadColumn(ColumnIdRep col_id, QLExprResultWriter result_writer) const { |
653 | 662M | auto value = GetColumn(col_id); |
654 | 662M | if (value == nullptr) { |
655 | 2.95k | result_writer.SetNull(); |
656 | 2.95k | return Status::OK(); |
657 | 2.95k | } |
658 | | |
659 | 662M | result_writer.SetExisting(value); |
660 | 662M | return Status::OK(); |
661 | 662M | } |
662 | | |
663 | | CHECKED_STATUS QLTableRow::ReadSubscriptedColumn(const QLSubscriptedColPB& subcol, |
664 | | const QLValuePB& index_arg, |
665 | 192 | QLExprResultWriter result_writer) const { |
666 | 192 | const auto* value = GetColumn(subcol.column_id()); |
667 | 192 | if (!value) { |
668 | | // Does not exist. |
669 | 0 | result_writer.SetNull(); |
670 | 0 | return Status::OK(); |
671 | 0 | } |
672 | | |
673 | 192 | if (value->has_map_value()) { |
674 | | // map['key'] |
675 | 147 | auto& map = value->map_value(); |
676 | 148 | for (int i = 0; i < map.keys_size(); i++1 ) { |
677 | 147 | if (map.keys(i) == index_arg) { |
678 | 146 | result_writer.SetExisting(&map.values(i)); |
679 | 146 | return Status::OK(); |
680 | 146 | } |
681 | 147 | } |
682 | 147 | } else if (45 value->has_list_value()45 ) { |
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 | 24 | } |
692 | 24 | } |
693 | | |
694 | 23 | result_writer.SetNull(); |
695 | 23 | return Status::OK(); |
696 | 192 | } |
697 | | |
698 | 7.16M | Result<const QLTableColumn&> QLTableRow::Column(ColumnIdRep col_id) const { |
699 | 7.16M | const auto* column = FindColumn(col_id); |
700 | 7.16M | if (column == nullptr) { |
701 | | // Does not exist. |
702 | 0 | return STATUS(InternalError, "Column unexpectedly not found in cache"); |
703 | 0 | } |
704 | | |
705 | 7.16M | return *column; |
706 | 7.16M | } |
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 | 0 | return Status::OK(); |
711 | 41 | } |
712 | | |
713 | 5.52k | CHECKED_STATUS QLTableRow::GetWriteTime(ColumnIdRep col_id, int64_t *write_time) const { |
714 | 5.52k | const QLTableColumn& column = VERIFY_RESULT(Column(col_id)); |
715 | 0 | DCHECK_NE(QLTableColumn::kUninitializedWriteTime, column.write_time) << "Column id: " << col_id; |
716 | 5.52k | *write_time = column.write_time; |
717 | 5.52k | return Status::OK(); |
718 | 5.52k | } |
719 | | |
720 | 7.16M | CHECKED_STATUS QLTableRow::GetValue(ColumnIdRep col_id, QLValue *column) const { |
721 | 7.16M | *column = VERIFY_RESULT(Column(col_id)).get().value; |
722 | 0 | return Status::OK(); |
723 | 7.16M | } |
724 | | |
725 | 7.16M | CHECKED_STATUS QLTableRow::GetValue(const ColumnId& col, QLValue *column) const { |
726 | 7.16M | return GetValue(col.rep(), column); |
727 | 7.16M | } |
728 | | |
729 | 49.9M | boost::optional<const QLValuePB&> QLTableRow::GetValue(ColumnIdRep col_id) const { |
730 | 49.9M | const auto* column = FindColumn(col_id); |
731 | 49.9M | if (column) { |
732 | 49.9M | return column->value; |
733 | 49.9M | } |
734 | 7.39k | return boost::none; |
735 | 49.9M | } |
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 | 41.2k | bool QLTableRow::MatchColumn(ColumnIdRep col_id, const QLTableRow& source) const { |
751 | 41.2k | const auto* this_column = FindColumn(col_id); |
752 | 41.2k | const auto* source_column = source.FindColumn(col_id); |
753 | 41.3k | if (this_column41.2k && source_column) { |
754 | 31.8k | return this_column->value == source_column->value; |
755 | 31.8k | } |
756 | 9.47k | return !this_column && !source_column10 ; |
757 | 41.2k | } |
758 | | |
759 | 56.4M | QLTableColumn& QLTableRow::AppendColumn() { |
760 | 56.4M | values_.emplace_back(); |
761 | 56.4M | assigned_.push_back(true); |
762 | 56.4M | ++num_assigned_; |
763 | 56.4M | return values_.back(); |
764 | 56.4M | } |
765 | | |
766 | 774M | QLTableColumn& QLTableRow::AllocColumn(ColumnIdRep col_id) { |
767 | 774M | size_t index = col_id; |
768 | 774M | if (index < kFirstNonPreallocatedColumnId && index >= kFirstColumnIdRep460M ) { |
769 | 459M | index -= kFirstColumnIdRep; |
770 | | // We are in directly mapped part. Ensure that vector is big enough. |
771 | 459M | if (values_.size() <= index) { |
772 | | // We don't need reserve here, because no allocation would take place. |
773 | 46.0M | if (values_.size() < index) { |
774 | 66.8k | values_.resize(index); |
775 | 66.8k | assigned_.resize(index); |
776 | 66.8k | } |
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 | 46.0M | return AppendColumn(); |
780 | 46.0M | } |
781 | 459M | } 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 | 314M | if (values_.size() < kPreallocatedSize) { |
785 | 205k | values_.resize(kPreallocatedSize); |
786 | 205k | assigned_.resize(kPreallocatedSize); |
787 | 205k | } |
788 | 314M | auto iterator_and_flag = column_id_to_index_.emplace(col_id, values_.size()); |
789 | 314M | if (iterator_and_flag.second) { |
790 | 10.4M | return AppendColumn(); |
791 | 10.4M | } |
792 | 304M | index = iterator_and_flag.first->second; |
793 | 304M | } |
794 | | |
795 | 718M | if (!assigned_[index]) { |
796 | 664M | assigned_[index] = true; |
797 | 664M | ++num_assigned_; |
798 | 664M | } |
799 | 718M | return values_[index]; |
800 | 774M | } |
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 | 28.7M | QLTableColumn& QLTableRow::AllocColumn(ColumnIdRep col_id, const QLValuePB& ql_value) { |
807 | 28.7M | QLTableColumn& result = AllocColumn(col_id); |
808 | 28.7M | result.value = ql_value; |
809 | 28.7M | return result; |
810 | 28.7M | } |
811 | | |
812 | 77.1k | QLTableColumn& QLTableRow::AllocColumn(ColumnIdRep col_id, QLValuePB&& ql_value) { |
813 | 77.1k | QLTableColumn& result = AllocColumn(col_id); |
814 | 77.1k | result.value = std::move(ql_value); |
815 | 77.1k | return result; |
816 | 77.1k | } |
817 | | |
818 | 413 | void QLTableRow::CopyColumn(ColumnIdRep col_id, const QLTableRow& source) { |
819 | 413 | const auto* value = source.FindColumn(col_id); |
820 | 413 | if (value) { |
821 | 413 | AllocColumn(col_id) = *value; |
822 | 413 | return; |
823 | 413 | } |
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; ++i1 ) { |
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 | 1 | 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++15.4k ) { |
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 | 15.1k | } 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 | 18.0k | void QLExprResult::MoveToJsonb(common::Jsonb* out) { |
878 | 18.0k | if (existing_value_) { |
879 | 18.0k | out->Assign(existing_value_->jsonb_value()); |
880 | 18.0k | existing_value_ = nullptr; |
881 | 18.0k | } else { |
882 | 0 | out->Assign(std::move(*value_.mutable_value()->mutable_jsonb_value())); |
883 | 0 | } |
884 | 18.0k | } |
885 | | |
886 | 760M | const QLValuePB& QLExprResult::Value() const { |
887 | 760M | if (existing_value_) { |
888 | 719M | return *existing_value_; |
889 | 719M | } |
890 | | |
891 | 41.1M | return value_.value(); |
892 | 760M | } |
893 | | |
894 | 18.2k | bool QLExprResult::IsNull() const { |
895 | 18.2k | if (existing_value_) { |
896 | 18.1k | return yb::IsNull(*existing_value_); |
897 | 18.1k | } |
898 | | |
899 | 89 | return value_.IsNull(); |
900 | 18.2k | } |
901 | | |
902 | 4.95k | void QLExprResult::MoveTo(QLValuePB* out) { |
903 | 4.95k | 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.95k | } |
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 | 761M | QLExprResultWriter QLExprResult::Writer() { |
921 | 761M | return QLExprResultWriter(this); |
922 | 761M | } |
923 | | |
924 | 3.19k | void QLExprResultWriter::SetNull() { |
925 | 3.19k | result_->value_.SetNull(); |
926 | 3.19k | } |
927 | | |
928 | 717M | void QLExprResultWriter::SetExisting(const QLValuePB* existing_value) { |
929 | 717M | result_->existing_value_ = existing_value; |
930 | 717M | } |
931 | | |
932 | 44.4M | QLValue& QLExprResultWriter::NewValue() { |
933 | 44.4M | return result_->value_; |
934 | 44.4M | } |
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 | 1 | std::to_string(write_time)0 ); |
940 | 1 | } |
941 | | |
942 | | } // namespace yb |