YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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
38.6M
DocExprExecutor::DocExprExecutor() {}
42
43
38.6M
DocExprExecutor::~DocExprExecutor() {}
44
45
CHECKED_STATUS DocExprExecutor::EvalColumnRef(ColumnIdRep col_id,
46
                                              const QLTableRow* table_row,
47
656M
                                              QLExprResultWriter result_writer) {
48
  // Return NULL value if row is not provided.
49
656M
  if (table_row == nullptr) {
50
0
    result_writer.SetNull();
51
0
    return Status::OK();
52
0
  }
53
54
  // Read value from given row.
55
656M
  if (col_id >= 0) {
56
615M
    return table_row->ReadColumn(col_id, result_writer);
57
615M
  }
58
59
  // Read key of the given row.
60
41.2M
  
if (41.0M
col_id == static_cast<int>(PgSystemAttrNum::kYBTupleId)41.0M
) {
61
41.2M
    return GetTupleId(&result_writer.NewValue());
62
41.2M
  }
63
64
18.4E
  return STATUS_SUBSTITUTE(InvalidArgument, "Invalid column ID: $0", col_id);
65
41.0M
}
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
20.7k
                                           const Schema *schema) {
78
20.7k
  bfql::TSOpcode tsopcode = static_cast<bfql::TSOpcode>(tscall.opcode());
79
20.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
41
      DCHECK_EQ
(tscall.operands().size(), 1) << "WriteTime takes only one argument, a column"0
;
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
38
      } else {
93
3
        result->SetNull();
94
3
      }
95
41
      return Status::OK();
96
41
    }
97
98
5.51k
    case bfql::TSOpcode::kWriteTime: {
99
5.51k
      DCHECK_EQ
(tscall.operands().size(), 1) << "WriteTime takes only one argument, a column"0
;
100
5.51k
      int64_t write_time = 0;
101
5.51k
      RETURN_NOT_OK(table_row.GetWriteTime(tscall.operands(0).column_id(), &write_time));
102
5.51k
      result->set_int64_value(write_time);
103
5.51k
      return Status::OK();
104
5.51k
    }
105
106
13.5k
    case bfql::TSOpcode::kCount:
107
13.5k
      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
117
      }
115
13.5k
      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()3
) {
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
20.7k
  }
192
193
0
  result->SetNull();
194
0
  return Status::OK();
195
20.7k
}
196
197
CHECKED_STATUS DocExprExecutor::EvalTSCall(const PgsqlBCallPB& tscall,
198
                                           const QLTableRow& table_row,
199
                                           QLValue *result,
200
3.14M
                                           const Schema *schema) {
201
3.14M
  bfpg::TSOpcode tsopcode = static_cast<bfpg::TSOpcode>(tscall.opcode());
202
3.14M
  switch (tsopcode) {
203
3.12M
    case bfpg::TSOpcode::kCount: {
204
3.12M
      const auto& operand = tscall.operands(0);
205
3.12M
      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
5
        QLExprResult arg_result;
209
5
        RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer()));
210
5
        if (IsNull(arg_result.Value())) {
211
0
          return Status::OK();
212
0
        }
213
3.13M
      } else 
if (3.12M
operand.has_value()3.12M
&& QLValue::IsNull(operand.value())) {
214
        // We've got COUNT(null) which is bound to return zero.
215
5.00k
        return Status::OK();
216
5.00k
      }
217
3.12M
      return EvalCount(result);
218
3.12M
    }
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
0
    case bfpg::TSOpcode::kSumInt16:
226
0
      return EvalSumInt(tscall.operands(0), table_row, result, [](const QLValuePB& value) {
227
0
        return value.int16_value();
228
0
      });
229
230
1.00k
    case bfpg::TSOpcode::kSumInt32:
231
1.00k
      return EvalSumInt(tscall.operands(0), table_row, result, [](const QLValuePB& value) {
232
1.00k
        return value.int32_value();
233
1.00k
      });
234
235
10.0k
    case bfpg::TSOpcode::kSumInt64:
236
10.0k
      return EvalSumInt(tscall.operands(0), table_row, result, [](const QLValuePB& value) {
237
5.00k
        return value.int64_value();
238
5.00k
      });
239
240
0
    case bfpg::TSOpcode::kSumFloat:
241
0
      return EvalSumReal(
242
0
          tscall.operands(0), table_row, result,
243
0
          [](const QLValuePB& value) { return value.float_value(); },
244
0
          [](float value, QLValuePB* out) { return out->set_float_value(value); });
245
246
0
    case bfpg::TSOpcode::kSumDouble:
247
0
      return EvalSumReal(
248
0
          tscall.operands(0), table_row, result,
249
0
          [](const QLValuePB& value) { return value.double_value(); },
250
0
          [](double value, QLValuePB* out) { return out->set_double_value(value); });
251
252
88
    case bfpg::TSOpcode::kMin: {
253
88
      QLExprResult arg_result;
254
88
      RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer()));
255
88
      return EvalMin(arg_result.Value(), result);
256
88
    }
257
258
1.88k
    case bfpg::TSOpcode::kMax: {
259
1.88k
      QLExprResult arg_result;
260
1.88k
      RETURN_NOT_OK(EvalExpr(tscall.operands(0), table_row, arg_result.Writer()));
261
1.88k
      return EvalMax(arg_result.Value(), result);
262
1.88k
    }
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
1.88k
    }
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
3.14M
  }
276
277
0
  result->SetNull();
278
0
  return Status::OK();
279
3.14M
}
280
281
//--------------------------------------------------------------------------------------------------
282
283
3.13M
CHECKED_STATUS DocExprExecutor::EvalCount(QLValue *aggr_count) {
284
3.13M
  if (aggr_count->IsNull()) {
285
16.3k
    aggr_count->set_int64_value(1);
286
3.12M
  } else {
287
3.12M
    aggr_count->set_int64_value(aggr_count->int64_value() + 1);
288
3.12M
  }
289
3.13M
  return Status::OK();
290
3.13M
}
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
65
    *aggr_sum = val;
299
65
    return Status::OK();
300
65
  }
301
302
408
  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
36
    case InternalType::kInt32Value:
310
36
      aggr_sum->set_int32_value(aggr_sum->int32_value() + val.int32_value());
311
36
      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
408
  }
335
408
  return Status::OK();
336
408
}
337
338
template <class Extractor>
339
CHECKED_STATUS DocExprExecutor::EvalSumInt(
340
    const PgsqlExpressionPB& operand, const QLTableRow& table_row, QLValue *aggr_sum,
341
11.0k
    const Extractor& extractor) {
342
11.0k
  QLExprResult arg_result;
343
11.0k
  RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer()));
344
11.0k
  const auto& val = arg_result.Value();
345
346
11.0k
  if (IsNull(val)) {
347
5.00k
    return Status::OK();
348
5.00k
  }
349
350
6.00k
  if (aggr_sum->IsNull()) {
351
12
    aggr_sum->set_int64_value(extractor(val));
352
5.99k
  } else {
353
5.99k
    aggr_sum->set_int64_value(aggr_sum->int64_value() + extractor(val));
354
5.99k
  }
355
356
6.00k
  return Status::OK();
357
11.0k
}
Unexecuted instantiation: doc_expr.cc:yb::Status yb::docdb::DocExprExecutor::EvalSumInt<yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_0>(yb::PgsqlExpressionPB const&, yb::QLTableRow const&, yb::QLValue*, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_0 const&)
Unexecuted instantiation: doc_expr.cc:yb::Status yb::docdb::DocExprExecutor::EvalSumInt<yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_1>(yb::PgsqlExpressionPB const&, yb::QLTableRow const&, yb::QLValue*, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_1 const&)
doc_expr.cc:yb::Status yb::docdb::DocExprExecutor::EvalSumInt<yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_2>(yb::PgsqlExpressionPB const&, yb::QLTableRow const&, yb::QLValue*, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_2 const&)
Line
Count
Source
341
1.00k
    const Extractor& extractor) {
342
1.00k
  QLExprResult arg_result;
343
1.00k
  RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer()));
344
1.00k
  const auto& val = arg_result.Value();
345
346
1.00k
  if (IsNull(val)) {
347
0
    return Status::OK();
348
0
  }
349
350
1.00k
  if (aggr_sum->IsNull()) {
351
9
    aggr_sum->set_int64_value(extractor(val));
352
997
  } else {
353
997
    aggr_sum->set_int64_value(aggr_sum->int64_value() + extractor(val));
354
997
  }
355
356
1.00k
  return Status::OK();
357
1.00k
}
doc_expr.cc:yb::Status yb::docdb::DocExprExecutor::EvalSumInt<yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_3>(yb::PgsqlExpressionPB const&, yb::QLTableRow const&, yb::QLValue*, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_3 const&)
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
3
    aggr_sum->set_int64_value(extractor(val));
352
4.99k
  } else {
353
4.99k
    aggr_sum->set_int64_value(aggr_sum->int64_value() + extractor(val));
354
4.99k
  }
355
356
5.00k
  return Status::OK();
357
10.0k
}
358
359
template <class Extractor, class Setter>
360
CHECKED_STATUS DocExprExecutor::EvalSumReal(
361
    const PgsqlExpressionPB& operand, const QLTableRow& table_row, QLValue *aggr_sum,
362
0
    const Extractor& extractor, const Setter& setter) {
363
0
  QLExprResult arg_result;
364
0
  RETURN_NOT_OK(EvalExpr(operand, table_row, arg_result.Writer()));
365
0
  const auto& val = arg_result.Value();
366
367
0
  if (IsNull(val)) {
368
0
    return Status::OK();
369
0
  }
370
371
0
  if (aggr_sum->IsNull()) {
372
0
    setter(extractor(val), aggr_sum->mutable_value());
373
0
  } else {
374
0
    setter(extractor(aggr_sum->value()) + extractor(val), aggr_sum->mutable_value());
375
0
  }
376
377
0
  return Status::OK();
378
0
}
Unexecuted instantiation: doc_expr.cc:yb::Status yb::docdb::DocExprExecutor::EvalSumReal<yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_4, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_5>(yb::PgsqlExpressionPB const&, yb::QLTableRow const&, yb::QLValue*, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_4 const&, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_5 const&)
Unexecuted instantiation: doc_expr.cc:yb::Status yb::docdb::DocExprExecutor::EvalSumReal<yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_6, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_7>(yb::PgsqlExpressionPB const&, yb::QLTableRow const&, yb::QLValue*, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_6 const&, yb::docdb::DocExprExecutor::EvalTSCall(yb::PgsqlBCallPB const&, yb::QLTableRow const&, yb::QLValue*, yb::Schema const*)::$_7 const&)
379
380
2.61k
CHECKED_STATUS DocExprExecutor::EvalMax(const QLValuePB& val, QLValue *aggr_max) {
381
2.61k
  if (!IsNull(val) && 
(2.61k
aggr_max->IsNull()2.61k
||
aggr_max->value() < val2.49k
)) {
382
249
    *aggr_max = val;
383
249
  }
384
2.61k
  return Status::OK();
385
2.61k
}
386
387
414
CHECKED_STATUS DocExprExecutor::EvalMin(const QLValuePB& val, QLValue *aggr_min) {
388
414
  if (!IsNull(val) && 
(409
aggr_min->IsNull()409
||
aggr_min->value() > val310
)) {
389
133
    *aggr_min = val;
390
133
  }
391
414
  return Status::OK();
392
414
}
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::kMapValue2
) {
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(); 
++i6
) {
431
6
      map->mutable_keys(i)->set_string_value(field_names[i]);
432
6
    }
433
40
  } else if (type->IsFrozen() && 
value->value_case() == QLValuePB::kFrozenValue23
) {
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(); 
++i30
) {
444
30
          map->add_keys()->set_string_value(field_names[i]);
445
30
          *(map->add_values()) = seq.elems(i);
446
30
        }
447
15
      }
448
15
    } else 
if (8
type->param_type()->main() == MAP8
) {
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(); 
++i15
) {
468
15
        UnpackUDTAndFrozen(type->param_type()->param_type(), seq->mutable_elems(i));
469
15
      }
470
7
    }
471
23
  } else 
if (17
type->main() == LIST17
&&
value->value_case() == QLValuePB::kListValue1
) {
472
1
    QLSeqValuePB* seq = value->mutable_list_value();
473
3
    for (int i = 0; i < seq->elems_size(); 
++i2
) {
474
2
      UnpackUDTAndFrozen(type->param_type(), seq->mutable_elems(i));
475
2
    }
476
16
  } else if (type->main() == SET && 
value->value_case() == QLValuePB::kSetValue2
) {
477
2
    QLSeqValuePB* seq = value->mutable_set_value();
478
4
    for (int i = 0; i < seq->elems_size(); 
++i2
) {
479
2
      UnpackUDTAndFrozen(type->param_type(), seq->mutable_elems(i));
480
2
    }
481
14
  } else if (type->main() == MAP && 
value->value_case() == QLValuePB::kMapValue4
) {
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(); 
++i5
) {
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