/Users/deen/code/yugabyte-db/src/yb/docdb/doc_expr.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //-------------------------------------------------------------------------------------------------- |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | //-------------------------------------------------------------------------------------------------- |
4 | | |
5 | | #include "yb/docdb/doc_expr.h" |
6 | | |
7 | | #include <iostream> |
8 | | #include <string> |
9 | | |
10 | | #include "yb/bfql/bfunc_standard.h" |
11 | | |
12 | | #include "yb/common/jsonb.h" |
13 | | #include "yb/common/pg_system_attr.h" |
14 | | #include "yb/common/pgsql_protocol.pb.h" |
15 | | #include "yb/common/ql_datatype.h" |
16 | | #include "yb/common/ql_type.h" |
17 | | #include "yb/common/ql_value.h" |
18 | | #include "yb/common/schema.h" |
19 | | |
20 | | #include "yb/docdb/docdb_pgapi.h" |
21 | | |
22 | | #include "yb/gutil/endian.h" |
23 | | #include "yb/gutil/strings/escaping.h" |
24 | | |
25 | | #include "yb/util/date_time.h" |
26 | | #include "yb/util/decimal.h" |
27 | | #include "yb/util/enums.h" |
28 | | #include "yb/util/logging.h" |
29 | | #include "yb/util/net/inetaddress.h" |
30 | | #include "yb/util/result.h" |
31 | | #include "yb/util/status_format.h" |
32 | | #include "yb/util/uuid.h" |
33 | | |
34 | | namespace yb { |
35 | | namespace docdb { |
36 | | |
37 | | using yb::util::Decimal; |
38 | | |
39 | | //-------------------------------------------------------------------------------------------------- |
40 | | |
41 | 16.9M | DocExprExecutor::DocExprExecutor() {} |
42 | | |
43 | 16.9M | DocExprExecutor::~DocExprExecutor() {} |
44 | | |
45 | | CHECKED_STATUS DocExprExecutor::EvalColumnRef(ColumnIdRep col_id, |
46 | | const QLTableRow* table_row, |
47 | 228M | QLExprResultWriter result_writer) { |
48 | | // Return NULL value if row is not provided. |
49 | 228M | if (table_row == nullptr) { |
50 | 0 | result_writer.SetNull(); |
51 | 0 | return Status::OK(); |
52 | 0 | } |
53 | | |
54 | | // Read value from given row. |
55 | 228M | if (col_id >= 0) { |
56 | 213M | return table_row->ReadColumn(col_id, result_writer); |
57 | 213M | } |
58 | | |
59 | | // Read key of the given row. |
60 | 15.2M | if (col_id == static_cast<int>(PgSystemAttrNum::kYBTupleId)) { |
61 | 15.2M | return GetTupleId(&result_writer.NewValue()); |
62 | 15.2M | } |
63 | | |
64 | 18.4E | return STATUS_SUBSTITUTE(InvalidArgument, "Invalid column ID: $0", col_id); |
65 | 18.4E | } |
66 | | |
67 | 0 | CHECKED_STATUS DocExprExecutor::GetTupleId(QLValue *result) const { |
68 | 0 | result->SetNull(); |
69 | 0 | return Status::OK(); |
70 | 0 | } |
71 | | |
72 | | //-------------------------------------------------------------------------------------------------- |
73 | | |
74 | | CHECKED_STATUS DocExprExecutor::EvalTSCall(const QLBCallPB& tscall, |
75 | | const QLTableRow& table_row, |
76 | | QLValue *result, |
77 | 22.7k | const Schema *schema) { |
78 | 22.7k | bfql::TSOpcode tsopcode = static_cast<bfql::TSOpcode>(tscall.opcode()); |
79 | 22.7k | switch (tsopcode) { |
80 | 0 | case bfql::TSOpcode::kNoOp: |
81 | 0 | case bfql::TSOpcode::kScalarInsert: |
82 | 0 | LOG(FATAL) << "Client should not generate function call instruction with operator " |
83 | 0 | << static_cast<int>(tsopcode); |
84 | 0 | break; |
85 | |
|
86 | 41 | case bfql::TSOpcode::kTtl: { |
87 | 0 | DCHECK_EQ(tscall.operands().size(), 1) << "WriteTime takes only one argument, a column"; |
88 | 41 | int64_t ttl_seconds = -1; |
89 | 41 | RETURN_NOT_OK(table_row.GetTTL(tscall.operands(0).column_id(), &ttl_seconds)); |
90 | 41 | if (ttl_seconds != -1) { |
91 | 38 | result->set_int64_value(ttl_seconds); |
92 | 3 | } else { |
93 | 3 | result->SetNull(); |
94 | 3 | } |
95 | 41 | return Status::OK(); |
96 | 41 | } |
97 | | |
98 | 5.93k | case bfql::TSOpcode::kWriteTime: { |
99 | 0 | DCHECK_EQ(tscall.operands().size(), 1) << "WriteTime takes only one argument, a column"; |
100 | 5.93k | int64_t write_time = 0; |
101 | 5.93k | RETURN_NOT_OK(table_row.GetWriteTime(tscall.operands(0).column_id(), &write_time)); |
102 | 5.93k | result->set_int64_value(write_time); |
103 | 5.93k | return Status::OK(); |
104 | 5.93k | } |
105 | | |
106 | 15.1k | case bfql::TSOpcode::kCount: |
107 | 15.1k | if (tscall.operands(0).has_column_id()) { |
108 | | // Check if column value is NULL. CQL does not count NULL value of a column. |
109 | 117 | QLExprResult arg_result; |
110 | 117 | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer())); |
111 | 117 | if (IsNull(arg_result.Value())) { |
112 | 2 | return Status::OK(); |
113 | 2 | } |
114 | 15.1k | } |
115 | 15.1k | return EvalCount(result); |
116 | | |
117 | 388 | case bfql::TSOpcode::kSum: { |
118 | 388 | QLExprResult arg_result; |
119 | 388 | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer())); |
120 | 388 | return EvalSum(arg_result.Value(), result); |
121 | 388 | } |
122 | | |
123 | 326 | case bfql::TSOpcode::kMin: { |
124 | 326 | QLExprResult arg_result; |
125 | 326 | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer())); |
126 | 326 | return EvalMin(arg_result.Value(), result); |
127 | 326 | } |
128 | | |
129 | 726 | case bfql::TSOpcode::kMax: { |
130 | 726 | QLExprResult arg_result; |
131 | 726 | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer())); |
132 | 726 | return EvalMax(arg_result.Value(), result); |
133 | 726 | } |
134 | | |
135 | 150 | case bfql::TSOpcode::kAvg: { |
136 | 150 | QLExprResult arg_result; |
137 | 150 | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer())); |
138 | 150 | return EvalAvg(arg_result.Value(), result); |
139 | 150 | } |
140 | | |
141 | 9 | case bfql::TSOpcode::kMapExtend: FALLTHROUGH_INTENDED; |
142 | 14 | case bfql::TSOpcode::kMapRemove: FALLTHROUGH_INTENDED; |
143 | 24 | case bfql::TSOpcode::kSetExtend: FALLTHROUGH_INTENDED; |
144 | 29 | case bfql::TSOpcode::kSetRemove: FALLTHROUGH_INTENDED; |
145 | 38 | case bfql::TSOpcode::kListAppend: { |
146 | | // Return the value of the second operand. The first operand must be a column ID. |
147 | 38 | QLExprResult temp; |
148 | 38 | RETURN_NOT_OK(EvalExpr(tscall.operands(1), table_row, temp.Writer())); |
149 | 38 | temp.MoveTo(result->mutable_value()); |
150 | 38 | return Status::OK(); |
151 | 38 | } |
152 | 5 | case bfql::TSOpcode::kListPrepend: { |
153 | | // Return the value of the first operand. The second operand is a column ID. |
154 | 5 | QLExprResult temp; |
155 | 5 | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, temp.Writer())); |
156 | 5 | temp.MoveTo(result->mutable_value()); |
157 | 5 | return Status::OK(); |
158 | 5 | } |
159 | 5 | case bfql::TSOpcode::kListRemove: { |
160 | 5 | QLExprResult org_list_result; |
161 | 5 | QLExprResult sub_list_result; |
162 | 5 | RETURN_NOT_OK(EvalOperands( |
163 | 5 | this, tscall.operands(), table_row, org_list_result.Writer(), sub_list_result.Writer())); |
164 | 5 | QLValue org_list_value; |
165 | 5 | QLValue sub_list_value; |
166 | 5 | org_list_result.MoveTo(org_list_value.mutable_value()); |
167 | 5 | sub_list_result.MoveTo(sub_list_value.mutable_value()); |
168 | | |
169 | 5 | result->set_list_value(); |
170 | 5 | if (!org_list_value.IsNull() && !sub_list_value.IsNull()) { |
171 | 3 | QLSeqValuePB* org_list = org_list_value.mutable_list_value(); |
172 | 3 | QLSeqValuePB* sub_list = sub_list_value.mutable_list_value(); |
173 | 9 | for (QLValuePB& org_elem : *org_list->mutable_elems()) { |
174 | 9 | bool should_remove = false; |
175 | 13 | for (QLValuePB& sub_elem : *sub_list->mutable_elems()) { |
176 | 13 | if (org_elem == sub_elem) { |
177 | 4 | should_remove = true; |
178 | 4 | break; |
179 | 4 | } |
180 | 13 | } |
181 | 9 | if (!should_remove) { |
182 | 5 | *result->add_list_elem() = std::move(org_elem); |
183 | 5 | } |
184 | 9 | } |
185 | 3 | } |
186 | 5 | return Status::OK(); |
187 | 5 | } |
188 | | |
189 | 11 | case bfql::TSOpcode::kToJson: |
190 | 11 | return EvalParametricToJson(tscall.operands(0), table_row, result, schema); |
191 | 0 | } |
192 | | |
193 | 0 | result->SetNull(); |
194 | 0 | return Status::OK(); |
195 | 0 | } |
196 | | |
197 | | CHECKED_STATUS DocExprExecutor::EvalTSCall(const PgsqlBCallPB& tscall, |
198 | | const QLTableRow& table_row, |
199 | | QLValue *result, |
200 | 1.71M | const Schema *schema) { |
201 | 1.71M | bfpg::TSOpcode tsopcode = static_cast<bfpg::TSOpcode>(tscall.opcode()); |
202 | 1.71M | switch (tsopcode) { |
203 | 1.63M | case bfpg::TSOpcode::kCount: { |
204 | 1.63M | const auto& operand = tscall.operands(0); |
205 | 1.63M | if (operand.has_column_id()) { |
206 | | // Check if column value is NULL. Postgres does not count NULL value of a column, unless |
207 | | // it's COUNT(*). |
208 | 1.26k | QLExprResult arg_result; |
209 | 1.26k | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); |
210 | 1.26k | if (IsNull(arg_result.Value())) { |
211 | 12 | return Status::OK(); |
212 | 12 | } |
213 | 1.63M | } else if (operand.has_value() && QLValue::IsNull(operand.value())) { |
214 | | // We've got COUNT(null) which is bound to return zero. |
215 | 5.10k | return Status::OK(); |
216 | 5.10k | } |
217 | 1.62M | return EvalCount(result); |
218 | 1.62M | } |
219 | | |
220 | 0 | case bfpg::TSOpcode::kSumInt8: |
221 | 0 | return EvalSumInt(tscall.operands(0), table_row, result, [](const QLValuePB& value) { |
222 | 0 | return value.int8_value(); |
223 | 0 | }); |
224 | | |
225 | 103 | case bfpg::TSOpcode::kSumInt16: |
226 | 103 | return EvalSumInt(tscall.operands(0), table_row, result, [](const QLValuePB& value) { |
227 | 103 | return value.int16_value(); |
228 | 103 | }); |
229 | | |
230 | 2.20k | case bfpg::TSOpcode::kSumInt32: |
231 | 2.20k | return EvalSumInt(tscall.operands(0), table_row, result, [](const QLValuePB& value) { |
232 | 2.20k | return value.int32_value(); |
233 | 2.20k | }); |
234 | | |
235 | 10.0k | case bfpg::TSOpcode::kSumInt64: |
236 | 5.00k | return EvalSumInt(tscall.operands(0), table_row, result, [](const QLValuePB& value) { |
237 | 5.00k | return value.int64_value(); |
238 | 5.00k | }); |
239 | | |
240 | 103 | case bfpg::TSOpcode::kSumFloat: |
241 | 103 | return EvalSumReal( |
242 | 103 | tscall.operands(0), table_row, result, |
243 | 202 | [](const QLValuePB& value) { return value.float_value(); }, |
244 | 104 | [](float value, QLValuePB* out) { return out->set_float_value(value); }); |
245 | | |
246 | 100 | case bfpg::TSOpcode::kSumDouble: |
247 | 100 | return EvalSumReal( |
248 | 100 | tscall.operands(0), table_row, result, |
249 | 197 | [](const QLValuePB& value) { return value.double_value(); }, |
250 | 100 | [](double value, QLValuePB* out) { return out->set_double_value(value); }); |
251 | | |
252 | 10.4k | case bfpg::TSOpcode::kMin: { |
253 | 10.4k | QLExprResult arg_result; |
254 | 10.4k | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer())); |
255 | 10.4k | return EvalMin(arg_result.Value(), result); |
256 | 10.4k | } |
257 | | |
258 | 62.4k | case bfpg::TSOpcode::kMax: { |
259 | 62.4k | QLExprResult arg_result; |
260 | 62.4k | RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer())); |
261 | 62.4k | return EvalMax(arg_result.Value(), result); |
262 | 62.4k | } |
263 | | |
264 | 0 | case bfpg::TSOpcode::kPgEvalExprCall: { |
265 | | // Support for serialized Postgres expression evaluation has been moved to separate class |
266 | | // DocPgExprExecutor, it should be instantiated to handle kPgEvalExprCall type of expressions |
267 | 0 | DCHECK(false); |
268 | 0 | return Status::OK(); |
269 | 62.4k | } |
270 | | |
271 | 0 | default: |
272 | 0 | LOG(FATAL) << "Client should not generate function call instruction with operator " |
273 | 0 | << static_cast<int>(tsopcode); |
274 | 0 | break; |
275 | 0 | } |
276 | | |
277 | 0 | result->SetNull(); |
278 | 0 | return Status::OK(); |
279 | 0 | } |
280 | | |
281 | | //-------------------------------------------------------------------------------------------------- |
282 | | |
283 | 1.64M | CHECKED_STATUS DocExprExecutor::EvalCount(QLValue *aggr_count) { |
284 | 1.64M | if (aggr_count->IsNull()) { |
285 | 396 | aggr_count->set_int64_value(1); |
286 | 1.64M | } else { |
287 | 1.64M | aggr_count->set_int64_value(aggr_count->int64_value() + 1); |
288 | 1.64M | } |
289 | 1.64M | return Status::OK(); |
290 | 1.64M | } |
291 | | |
292 | 478 | CHECKED_STATUS DocExprExecutor::EvalSum(const QLValuePB& val, QLValue *aggr_sum) { |
293 | 478 | if (IsNull(val)) { |
294 | 5 | return Status::OK(); |
295 | 5 | } |
296 | | |
297 | 473 | if (aggr_sum->IsNull()) { |
298 | 63 | *aggr_sum = val; |
299 | 63 | return Status::OK(); |
300 | 63 | } |
301 | | |
302 | 410 | switch (aggr_sum->type()) { |
303 | 0 | case InternalType::kInt8Value: |
304 | 0 | aggr_sum->set_int8_value(aggr_sum->int8_value() + val.int8_value()); |
305 | 0 | break; |
306 | 0 | case InternalType::kInt16Value: |
307 | 0 | aggr_sum->set_int16_value(aggr_sum->int16_value() + val.int16_value()); |
308 | 0 | break; |
309 | 38 | case InternalType::kInt32Value: |
310 | 38 | aggr_sum->set_int32_value(aggr_sum->int32_value() + val.int32_value()); |
311 | 38 | break; |
312 | 54 | case InternalType::kInt64Value: |
313 | 54 | aggr_sum->set_int64_value(aggr_sum->int64_value() + val.int64_value()); |
314 | 54 | break; |
315 | 113 | case InternalType::kVarintValue: |
316 | 113 | aggr_sum->set_varint_value(aggr_sum->varint_value() + QLValue::varint_value(val)); |
317 | 113 | break; |
318 | 36 | case InternalType::kFloatValue: |
319 | 36 | aggr_sum->set_float_value(aggr_sum->float_value() + val.float_value()); |
320 | 36 | break; |
321 | 54 | case InternalType::kDoubleValue: |
322 | 54 | aggr_sum->set_double_value(aggr_sum->double_value() + val.double_value()); |
323 | 54 | break; |
324 | 115 | case InternalType::kDecimalValue: { |
325 | 115 | Decimal sum, value; |
326 | 115 | RETURN_NOT_OK(sum.DecodeFromComparable(aggr_sum->decimal_value())); |
327 | 115 | RETURN_NOT_OK(value.DecodeFromComparable(val.decimal_value())); |
328 | 115 | sum = sum + value; |
329 | 115 | aggr_sum->set_decimal_value(sum.EncodeToComparable()); |
330 | 115 | break; |
331 | 115 | } |
332 | 0 | default: |
333 | 0 | return STATUS(RuntimeError, "Cannot find SUM of this column"); |
334 | 410 | } |
335 | 410 | return Status::OK(); |
336 | 410 | } |
337 | | |
338 | | template <class Extractor> |
339 | | CHECKED_STATUS DocExprExecutor::EvalSumInt( |
340 | | const PgsqlExpressionPB& operand, const QLTableRow& table_row, QLValue *aggr_sum, |
341 | 12.3k | const Extractor& extractor) { |
342 | 12.3k | QLExprResult arg_result; |
343 | 12.3k | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); |
344 | 12.3k | const auto& val = arg_result.Value(); |
345 | | |
346 | 12.3k | if (IsNull(val)) { |
347 | 5.00k | return Status::OK(); |
348 | 5.00k | } |
349 | | |
350 | 7.30k | if (aggr_sum->IsNull()) { |
351 | 25 | aggr_sum->set_int64_value(extractor(val)); |
352 | 7.28k | } else { |
353 | 7.28k | aggr_sum->set_int64_value(aggr_sum->int64_value() + extractor(val)); |
354 | 7.28k | } |
355 | | |
356 | 7.30k | return Status::OK(); |
357 | 7.30k | } Unexecuted instantiation: doc_expr.cc:_ZN2yb5docdb15DocExprExecutor10EvalSumIntIZNS1_10EvalTSCallERKNS_12PgsqlBCallPBERKNS_10QLTableRowEPNS_7QLValueEPKNS_6SchemaEE3$_0EENS_6StatusERKNS_17PgsqlExpressionPBES8_SA_RKT_ doc_expr.cc:_ZN2yb5docdb15DocExprExecutor10EvalSumIntIZNS1_10EvalTSCallERKNS_12PgsqlBCallPBERKNS_10QLTableRowEPNS_7QLValueEPKNS_6SchemaEE3$_1EENS_6StatusERKNS_17PgsqlExpressionPBES8_SA_RKT_ Line | Count | Source | 341 | 102 | const Extractor& extractor) { | 342 | 102 | QLExprResult arg_result; | 343 | 102 | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); | 344 | 102 | const auto& val = arg_result.Value(); | 345 | | | 346 | 102 | if (IsNull(val)) { | 347 | 0 | return Status::OK(); | 348 | 0 | } | 349 | | | 350 | 102 | if (aggr_sum->IsNull()) { | 351 | 5 | aggr_sum->set_int64_value(extractor(val)); | 352 | 97 | } else { | 353 | 97 | aggr_sum->set_int64_value(aggr_sum->int64_value() + extractor(val)); | 354 | 97 | } | 355 | | | 356 | 102 | return Status::OK(); | 357 | 102 | } |
doc_expr.cc:_ZN2yb5docdb15DocExprExecutor10EvalSumIntIZNS1_10EvalTSCallERKNS_12PgsqlBCallPBERKNS_10QLTableRowEPNS_7QLValueEPKNS_6SchemaEE3$_2EENS_6StatusERKNS_17PgsqlExpressionPBES8_SA_RKT_ Line | Count | Source | 341 | 2.20k | const Extractor& extractor) { | 342 | 2.20k | QLExprResult arg_result; | 343 | 2.20k | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); | 344 | 2.20k | const auto& val = arg_result.Value(); | 345 | | | 346 | 2.20k | if (IsNull(val)) { | 347 | 0 | return Status::OK(); | 348 | 0 | } | 349 | | | 350 | 2.20k | if (aggr_sum->IsNull()) { | 351 | 14 | aggr_sum->set_int64_value(extractor(val)); | 352 | 2.18k | } else { | 353 | 2.18k | aggr_sum->set_int64_value(aggr_sum->int64_value() + extractor(val)); | 354 | 2.18k | } | 355 | | | 356 | 2.20k | return Status::OK(); | 357 | 2.20k | } |
doc_expr.cc:_ZN2yb5docdb15DocExprExecutor10EvalSumIntIZNS1_10EvalTSCallERKNS_12PgsqlBCallPBERKNS_10QLTableRowEPNS_7QLValueEPKNS_6SchemaEE3$_3EENS_6StatusERKNS_17PgsqlExpressionPBES8_SA_RKT_ Line | Count | Source | 341 | 10.0k | const Extractor& extractor) { | 342 | 10.0k | QLExprResult arg_result; | 343 | 10.0k | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); | 344 | 10.0k | const auto& val = arg_result.Value(); | 345 | | | 346 | 10.0k | if (IsNull(val)) { | 347 | 5.00k | return Status::OK(); | 348 | 5.00k | } | 349 | | | 350 | 5.00k | if (aggr_sum->IsNull()) { | 351 | 6 | aggr_sum->set_int64_value(extractor(val)); | 352 | 5.00k | } else { | 353 | 5.00k | aggr_sum->set_int64_value(aggr_sum->int64_value() + extractor(val)); | 354 | 5.00k | } | 355 | | | 356 | 5.00k | return Status::OK(); | 357 | 5.00k | } |
|
358 | | |
359 | | template <class Extractor, class Setter> |
360 | | CHECKED_STATUS DocExprExecutor::EvalSumReal( |
361 | | const PgsqlExpressionPB& operand, const QLTableRow& table_row, QLValue *aggr_sum, |
362 | 204 | const Extractor& extractor, const Setter& setter) { |
363 | 204 | QLExprResult arg_result; |
364 | 204 | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); |
365 | 204 | const auto& val = arg_result.Value(); |
366 | | |
367 | 204 | if (IsNull(val)) { |
368 | 0 | return Status::OK(); |
369 | 0 | } |
370 | | |
371 | 204 | if (aggr_sum->IsNull()) { |
372 | 7 | setter(extractor(val), aggr_sum->mutable_value()); |
373 | 197 | } else { |
374 | 197 | setter(extractor(aggr_sum->value()) + extractor(val), aggr_sum->mutable_value()); |
375 | 197 | } |
376 | | |
377 | 204 | return Status::OK(); |
378 | 204 | } doc_expr.cc:_ZN2yb5docdb15DocExprExecutor11EvalSumRealIZNS1_10EvalTSCallERKNS_12PgsqlBCallPBERKNS_10QLTableRowEPNS_7QLValueEPKNS_6SchemaEE3$_4ZNS1_10EvalTSCallES5_S8_SA_SD_E3$_5EENS_6StatusERKNS_17PgsqlExpressionPBES8_SA_RKT_RKT0_ Line | Count | Source | 362 | 104 | const Extractor& extractor, const Setter& setter) { | 363 | 104 | QLExprResult arg_result; | 364 | 104 | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); | 365 | 104 | const auto& val = arg_result.Value(); | 366 | | | 367 | 104 | if (IsNull(val)) { | 368 | 0 | return Status::OK(); | 369 | 0 | } | 370 | | | 371 | 104 | if (aggr_sum->IsNull()) { | 372 | 4 | setter(extractor(val), aggr_sum->mutable_value()); | 373 | 100 | } else { | 374 | 100 | setter(extractor(aggr_sum->value()) + extractor(val), aggr_sum->mutable_value()); | 375 | 100 | } | 376 | | | 377 | 104 | return Status::OK(); | 378 | 104 | } |
doc_expr.cc:_ZN2yb5docdb15DocExprExecutor11EvalSumRealIZNS1_10EvalTSCallERKNS_12PgsqlBCallPBERKNS_10QLTableRowEPNS_7QLValueEPKNS_6SchemaEE3$_6ZNS1_10EvalTSCallES5_S8_SA_SD_E3$_7EENS_6StatusERKNS_17PgsqlExpressionPBES8_SA_RKT_RKT0_ Line | Count | Source | 362 | 100 | const Extractor& extractor, const Setter& setter) { | 363 | 100 | QLExprResult arg_result; | 364 | 100 | RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer())); | 365 | 100 | const auto& val = arg_result.Value(); | 366 | | | 367 | 100 | if (IsNull(val)) { | 368 | 0 | return Status::OK(); | 369 | 0 | } | 370 | | | 371 | 100 | if (aggr_sum->IsNull()) { | 372 | 3 | setter(extractor(val), aggr_sum->mutable_value()); | 373 | 97 | } else { | 374 | 97 | setter(extractor(aggr_sum->value()) + extractor(val), aggr_sum->mutable_value()); | 375 | 97 | } | 376 | | | 377 | 100 | return Status::OK(); | 378 | 100 | } |
|
379 | | |
380 | 63.1k | CHECKED_STATUS DocExprExecutor::EvalMax(const QLValuePB& val, QLValue *aggr_max) { |
381 | 63.1k | if (!IsNull(val) && (aggr_max->IsNull() || aggr_max->value() < val)) { |
382 | 366 | *aggr_max = val; |
383 | 366 | } |
384 | 63.1k | return Status::OK(); |
385 | 63.1k | } |
386 | | |
387 | 10.7k | CHECKED_STATUS DocExprExecutor::EvalMin(const QLValuePB& val, QLValue *aggr_min) { |
388 | 10.7k | if (!IsNull(val) && (aggr_min->IsNull() || aggr_min->value() > val)) { |
389 | 151 | *aggr_min = val; |
390 | 151 | } |
391 | 10.7k | return Status::OK(); |
392 | 10.7k | } |
393 | | |
394 | 150 | CHECKED_STATUS DocExprExecutor::EvalAvg(const QLValuePB& val, QLValue *aggr_avg) { |
395 | 150 | if (IsNull(val)) { |
396 | 5 | return Status::OK(); |
397 | 5 | } |
398 | | |
399 | 145 | QLValue sum, count; |
400 | | |
401 | 145 | if (aggr_avg->IsNull()) { |
402 | 55 | sum = val; |
403 | 55 | count.set_int64_value(1); |
404 | 55 | aggr_avg->set_map_value(); |
405 | 55 | *aggr_avg->add_map_key() = count.value(); |
406 | 55 | *aggr_avg->add_map_value() = sum.value(); |
407 | 55 | return Status::OK(); |
408 | 55 | } |
409 | | |
410 | 90 | QLMapValuePB* map = aggr_avg->mutable_map_value(); |
411 | 90 | sum = QLValue(map->values(0)); |
412 | 90 | RETURN_NOT_OK(EvalSum(val, &sum)); |
413 | 90 | count = QLValue(map->keys(0)); |
414 | 90 | count.set_int64_value(count.int64_value() + 1); |
415 | 90 | *map->mutable_keys(0) = count.value(); |
416 | 90 | *map->mutable_values(0) = sum.value(); |
417 | 90 | return Status::OK(); |
418 | 90 | } |
419 | | |
420 | | //-------------------------------------------------------------------------------------------------- |
421 | | |
422 | | namespace { |
423 | | |
424 | 42 | void UnpackUDTAndFrozen(const QLType::SharedPtr& type, QLValuePB* value) { |
425 | 42 | if (type->IsUserDefined() && value->value_case() == QLValuePB::kMapValue) { |
426 | | // Change MAP<field_index:field_value> into MAP<field_name:field_value> |
427 | | // in case of UDT. |
428 | 2 | const vector<string> field_names = type->udtype_field_names(); |
429 | 2 | QLMapValuePB* map = value->mutable_map_value(); |
430 | 8 | for (int i = 0; i < map->keys_size(); ++i) { |
431 | 6 | map->mutable_keys(i)->set_string_value(field_names[i]); |
432 | 6 | } |
433 | 40 | } else if (type->IsFrozen() && value->value_case() == QLValuePB::kFrozenValue) { |
434 | 23 | if (type->param_type()->IsUserDefined()) { |
435 | | // Change FROZEN[field_value,...] into MAP<field_name:field_value> |
436 | | // in case of FROZEN<UDT>. |
437 | 15 | const vector<string> field_names = type->param_type()->udtype_field_names(); |
438 | 15 | QLSeqValuePB seq(value->frozen_value()); |
439 | 15 | DCHECK_EQ(seq.elems_size(), field_names.size()); |
440 | 15 | QLMapValuePB* map = value->mutable_map_value(); |
441 | | |
442 | 15 | if (implicit_cast<size_t>(seq.elems_size()) == field_names.size()) { |
443 | 45 | for (int i = 0; i < seq.elems_size(); ++i) { |
444 | 30 | map->add_keys()->set_string_value(field_names[i]); |
445 | 30 | *(map->add_values()) = seq.elems(i); |
446 | 30 | } |
447 | 15 | } |
448 | 8 | } else if (type->param_type()->main() == MAP) { |
449 | | // Case: FROZEN<MAP>=[Key1,Value1,Key2,Value2] -> MAP<Key1:Value1, Key2:Value2>. |
450 | 1 | QLSeqValuePB seq(value->frozen_value()); |
451 | 1 | DCHECK_EQ(seq.elems_size() % 2, 0); |
452 | 1 | QLMapValuePB* map = value->mutable_map_value(); |
453 | | |
454 | 2 | for (int i = 0; i < seq.elems_size();) { |
455 | 1 | QLValuePB* const key = map->add_keys(); |
456 | 1 | *key = seq.elems(i++); |
457 | 1 | UnpackUDTAndFrozen(type->param_type()->keys_type(), key); |
458 | | |
459 | 1 | QLValuePB* const value = map->add_values(); |
460 | 1 | *value = seq.elems(i++); |
461 | 1 | UnpackUDTAndFrozen(type->param_type()->values_type(), value); |
462 | 1 | } |
463 | 7 | } else { |
464 | 7 | DCHECK(type->param_type()->main() == LIST || type->param_type()->main() == SET); |
465 | | // Case: FROZEN<LIST/SET> |
466 | 7 | QLSeqValuePB* seq = value->mutable_frozen_value(); |
467 | 22 | for (int i = 0; i < seq->elems_size(); ++i) { |
468 | 15 | UnpackUDTAndFrozen(type->param_type()->param_type(), seq->mutable_elems(i)); |
469 | 15 | } |
470 | 7 | } |
471 | 17 | } else if (type->main() == LIST && value->value_case() == QLValuePB::kListValue) { |
472 | 1 | QLSeqValuePB* seq = value->mutable_list_value(); |
473 | 3 | for (int i = 0; i < seq->elems_size(); ++i) { |
474 | 2 | UnpackUDTAndFrozen(type->param_type(), seq->mutable_elems(i)); |
475 | 2 | } |
476 | 16 | } else if (type->main() == SET && value->value_case() == QLValuePB::kSetValue) { |
477 | 2 | QLSeqValuePB* seq = value->mutable_set_value(); |
478 | 4 | for (int i = 0; i < seq->elems_size(); ++i) { |
479 | 2 | UnpackUDTAndFrozen(type->param_type(), seq->mutable_elems(i)); |
480 | 2 | } |
481 | 14 | } else if (type->main() == MAP && value->value_case() == QLValuePB::kMapValue) { |
482 | 4 | QLMapValuePB* map = value->mutable_map_value(); |
483 | 4 | DCHECK_EQ(map->keys_size(), map->values_size()); |
484 | 9 | for (int i = 0; i < map->keys_size(); ++i) { |
485 | 5 | UnpackUDTAndFrozen(type->keys_type(), map->mutable_keys(i)); |
486 | 5 | UnpackUDTAndFrozen(type->values_type(), map->mutable_values(i)); |
487 | 5 | } |
488 | 10 | } else if (type->main() == TUPLE) { |
489 | | // https://github.com/YugaByte/yugabyte-db/issues/936 |
490 | 0 | LOG(FATAL) << "Tuple type not implemented yet"; |
491 | 0 | } |
492 | 42 | } |
493 | | |
494 | | } // namespace |
495 | | |
496 | | CHECKED_STATUS DocExprExecutor::EvalParametricToJson(const QLExpressionPB& operand, |
497 | | const QLTableRow& table_row, |
498 | | QLValue *result, |
499 | 11 | const Schema *schema) { |
500 | 11 | QLExprResult val; |
501 | 11 | RETURN_NOT_OK(EvalExpr(operand, table_row, val.Writer(), schema)); |
502 | | |
503 | | // Repack parametric types like UDT, FROZEN, SET<FROZEN>, etc. |
504 | 11 | if (operand.has_column_id() && schema != nullptr) { |
505 | 11 | Result<const ColumnSchema&> col = schema->column_by_id(ColumnId(operand.column_id())); |
506 | 11 | DCHECK(col.ok()); |
507 | | |
508 | 11 | if (col.ok()) { |
509 | 11 | UnpackUDTAndFrozen(col->type(), val.ForceNewValue().mutable_value()); |
510 | 11 | } |
511 | 11 | } |
512 | | |
513 | | // Direct call of ToJson() for elementary type. |
514 | 11 | return bfql::ToJson(&val.ForceNewValue(), result); |
515 | 11 | } |
516 | | |
517 | | //-------------------------------------------------------------------------------------------------- |
518 | | |
519 | | } // namespace docdb |
520 | | } // namespace yb |