YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/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