YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/common/row.h
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
#ifndef YB_COMMON_ROW_H
33
#define YB_COMMON_ROW_H
34
35
#include <string>
36
#include <utility>
37
#include <vector>
38
39
#include "yb/common/common_fwd.h"
40
#include "yb/common/schema.h"
41
#include "yb/common/types.h"
42
43
#include "yb/gutil/macros.h"
44
45
#include "yb/util/bitmap.h"
46
#include "yb/util/memory/arena.h"
47
#include "yb/util/status.h"
48
49
namespace yb {
50
51
// A simple cell of data which directly corresponds to a pointer value.
52
// stack.
53
struct SimpleConstCell {
54
 public:
55
  // Both parameters must remain valid for the lifetime of the cell object.
56
  SimpleConstCell(const ColumnSchema* col_schema,
57
                  const void* value)
58
    : col_schema_(col_schema),
59
0
      value_(value) {
60
0
  }
61
62
  const TypeInfo* typeinfo() const;
63
  size_t size() const;
64
  bool is_nullable() const;
65
0
  const void* ptr() const { return value_; }
66
0
  bool is_null() const { return value_ == NULL; }
67
68
 private:
69
  const ColumnSchema* col_schema_;
70
  const void* value_;
71
};
72
73
// Copy the cell data from 'src' to 'dst'. This only copies the data, and not
74
// the null state. Use CopyCell() if you need to copy the null-ness.
75
//
76
// If dst_arena is non-NULL, relocates the data into the given arena.
77
template <class SrcCellType, class DstCellType, class ArenaType>
78
Status CopyCellData(const SrcCellType &src, DstCellType* dst, ArenaType *dst_arena) {
79
  DCHECK_EQ(src.typeinfo()->type(), dst->typeinfo()->type());
80
81
  if (src.typeinfo()->physical_type() == BINARY) {
82
    // If it's a Slice column, need to relocate the referred-to data
83
    // as well as the slice itself.
84
    // TODO: potential optimization here: if the new value is smaller than
85
    // the old value, we could potentially just overwrite in some cases.
86
    const Slice *src_slice = reinterpret_cast<const Slice *>(src.ptr());
87
    Slice *dst_slice = reinterpret_cast<Slice *>(dst->mutable_ptr());
88
    if (dst_arena != NULL) {
89
      if (PREDICT_FALSE(!dst_arena->RelocateSlice(*src_slice, dst_slice))) {
90
        return STATUS(IOError, "out of memory copying slice", src_slice->ToString());
91
      }
92
    } else {
93
      // Just copy the slice without relocating.
94
      // This is used by callers who know that the source row's data is going
95
      // to stick around for the scope of the destination.
96
      *dst_slice = *src_slice;
97
    }
98
  } else {
99
    memcpy(dst->mutable_ptr(), src.ptr(), src.size()); // TODO: inline?
100
  }
101
  return Status::OK();
102
}
103
104
// Copy the cell from 'src' to 'dst'.
105
//
106
// This copies the data, and relocates indirect data into the given arena,
107
// if it is not NULL.
108
template <class SrcCellType, class DstCellType, class ArenaType>
109
Status CopyCell(const SrcCellType &src, DstCellType* dst, ArenaType *dst_arena) {
110
  if (src.is_nullable()) {
111
    // Copy the null state.
112
    dst->set_null(src.is_null());
113
    if (src.is_null()) {
114
      // no need to copy any data contents once we marked the destination
115
      // cell as null.
116
      return Status::OK();
117
    }
118
  }
119
120
  return CopyCellData(src, dst, dst_arena);
121
}
122
123
// Copy all of the cells from one row to another. The two rows must share
124
// the same Schema. If they do not, use ProjectRow() below.
125
// This can be used to translate between columnar and row-wise layout, for example.
126
//
127
// If 'dst_arena' is set, then will relocate any indirect data to that arena
128
// during the copy.
129
template<class RowType1, class RowType2, class ArenaType>
130
inline CHECKED_STATUS CopyRow(const RowType1 &src_row, RowType2 *dst_row, ArenaType *dst_arena) {
131
  DCHECK_SCHEMA_EQ(*src_row.schema(), *dst_row->schema());
132
133
  for (int i = 0; i < src_row.schema()->num_columns(); i++) {
134
    typename RowType1::Cell src = src_row.cell(i);
135
    typename RowType2::Cell dst = dst_row->cell(i);
136
    RETURN_NOT_OK(CopyCell(src, &dst, dst_arena));
137
  }
138
139
  return Status::OK();
140
}
141
142
// Projection mapping for the specified schemas.
143
// A projection may contain:
144
//  - columns that are present in the "base schema"
145
//  - columns that are present in the "base schema" but with different types.
146
//    In this case an adapter should be used (e.g. INT8 to INT64, INT8 to STRING, ...)
147
//
148
// Example:
149
//  RowProjector projector.
150
//  projector.Init(base_schema, projection);
151
//  projector.ProjectRow(row_a, &row_b, &row_b_arena);
152
class RowProjector {
153
 public:
154
  typedef std::pair<size_t, size_t> ProjectionIdxMapping;
155
156
  // Construct a projector.
157
  // The two Schema pointers must remain valid for the lifetime of this object.
158
  RowProjector(const Schema* base_schema, const Schema* projection);
159
160
  // Initialize the projection mapping with the specified base_schema and projection
161
  CHECKED_STATUS Init();
162
163
  CHECKED_STATUS Reset(const Schema* base_schema, const Schema* projection);
164
165
  // Project a row from one schema into another, using the projection mapping.
166
  // Indirected data is copied into the provided dst arena.
167
  //
168
  // Use this method only on the read-path.
169
  template<class RowType1, class RowType2, class ArenaType>
170
  CHECKED_STATUS ProjectRowForRead(
171
      const RowType1& src_row, RowType2 *dst_row, ArenaType *dst_arena) const {
172
    return ProjectRow<RowType1, RowType2, ArenaType, true>(src_row, dst_row, dst_arena);
173
  }
174
175
  // Project a row from one schema into another, using the projection mapping.
176
  // Indirected data is copied into the provided dst arena.
177
  //
178
  // Use this method only on the write-path.
179
  template<class RowType1, class RowType2, class ArenaType>
180
  CHECKED_STATUS ProjectRowForWrite(const RowType1& src_row, RowType2 *dst_row,
181
                            ArenaType *dst_arena) const {
182
    return ProjectRow<RowType1, RowType2, ArenaType, false>(src_row, dst_row, dst_arena);
183
  }
184
185
0
  bool is_identity() const { return is_identity_; }
186
0
  const Schema* projection() const { return projection_; }
187
0
  const Schema* base_schema() const { return base_schema_; }
188
189
  // Returns the mapping between base schema and projection schema columns
190
  // first: is the projection column index, second: is the base_schema  index
191
10
  const vector<ProjectionIdxMapping>& base_cols_mapping() const { return base_cols_mapping_; }
192
193
  // Returns the mapping between base schema and projection schema columns
194
  // that requires a type adapter.
195
  // first: is the projection column index, second: is the base_schema  index
196
3
  const vector<ProjectionIdxMapping>& adapter_cols_mapping() const { return adapter_cols_mapping_; }
197
198
 private:
199
  friend class Schema;
200
201
6
  CHECKED_STATUS ProjectBaseColumn(size_t proj_col_idx, size_t base_col_idx) {
202
6
    base_cols_mapping_.push_back(ProjectionIdxMapping(proj_col_idx, base_col_idx));
203
6
    return Status::OK();
204
6
  }
205
206
0
  CHECKED_STATUS ProjectAdaptedColumn(size_t proj_col_idx, size_t base_col_idx) {
207
0
    adapter_cols_mapping_.push_back(ProjectionIdxMapping(proj_col_idx, base_col_idx));
208
0
    return Status::OK();
209
0
  }
210
211
  CHECKED_STATUS ProjectExtraColumn(size_t proj_col_idx);
212
213
 private:
214
  // Project a row from one schema into another, using the projection mapping.
215
  // Indirected data is copied into the provided dst arena.
216
  template<class RowType1, class RowType2, class ArenaType, bool FOR_READ>
217
  CHECKED_STATUS ProjectRow(
218
      const RowType1& src_row, RowType2 *dst_row, ArenaType *dst_arena) const {
219
    DCHECK_SCHEMA_EQ(*base_schema_, *src_row.schema());
220
    DCHECK_SCHEMA_EQ(*projection_, *dst_row->schema());
221
222
    // Copy directly from base Data
223
    for (const auto& base_mapping : base_cols_mapping_) {
224
      typename RowType1::Cell src_cell = src_row.cell(base_mapping.second);
225
      typename RowType2::Cell dst_cell = dst_row->cell(base_mapping.first);
226
      RETURN_NOT_OK(CopyCell(src_cell, &dst_cell, dst_arena));
227
    }
228
229
    // TODO: Copy Adapted base Data
230
    DCHECK(adapter_cols_mapping_.size() == 0) << "Value Adapter not supported yet";
231
232
    return Status::OK();
233
  }
234
235
 private:
236
  vector<ProjectionIdxMapping> base_cols_mapping_;
237
  vector<ProjectionIdxMapping> adapter_cols_mapping_;
238
239
  const Schema* base_schema_;
240
  const Schema* projection_;
241
  bool is_identity_;
242
243
  DISALLOW_COPY_AND_ASSIGN(RowProjector);
244
};
245
246
// Copy any indirect (eg STRING) data referenced by the given row into the
247
// provided arena.
248
//
249
// The row itself is mutated so that the indirect data points to the relocated
250
// storage.
251
template <class RowType, class ArenaType>
252
2
inline CHECKED_STATUS RelocateIndirectDataToArena(RowType *row, ArenaType *dst_arena) {
253
2
  const Schema* schema = row->schema();
254
  // For any Slice columns, copy the sliced data into the arena
255
  // and update the pointers
256
10
  for (size_t i = 0; i < schema->num_columns(); i++) {
257
8
    typename RowType::Cell cell = row->cell(i);
258
8
    if (cell.typeinfo()->physical_type() == BINARY) {
259
4
      if (cell.is_nullable() && cell.is_null()) {
260
0
        continue;
261
0
      }
262
263
4
      Slice *slice = reinterpret_cast<Slice *>(cell.mutable_ptr());
264
4
      if (!dst_arena->RelocateSlice(*slice, slice)) {
265
0
        return STATUS(IOError, "Unable to relocate slice");
266
0
      }
267
4
    }
268
8
  }
269
2
  return Status::OK();
270
2
}
271
272
class ContiguousRowHelper {
273
 public:
274
29
  static size_t null_bitmap_size(const Schema& schema) {
275
24
    return schema.has_nullables() ? BitmapSize(schema.num_columns()) : 0;
276
29
  }
277
278
0
  static uint8_t* null_bitmap_ptr(const Schema& schema, uint8_t* row_data) {
279
0
    return row_data + schema.byte_size();
280
0
  }
281
282
16
  static size_t row_size(const Schema& schema) {
283
16
    return schema.byte_size() + null_bitmap_size(schema);
284
16
  }
285
286
0
  static void InitNullsBitmap(const Schema& schema, Slice row_data) {
287
0
    InitNullsBitmap(schema, row_data.mutable_data(), row_data.size() - schema.byte_size());
288
0
  }
289
290
14
  static void InitNullsBitmap(const Schema& schema, uint8_t *row_data, size_t bitmap_size) {
291
14
    uint8_t *null_bitmap = row_data + schema.byte_size();
292
24
    for (size_t i = 0; i < bitmap_size; ++i) {
293
10
      null_bitmap[i] = 0x00;
294
10
    }
295
14
  }
296
297
17
  static bool is_null(const Schema& schema, const uint8_t *row_data, size_t col_idx) {
298
17
    DCHECK(schema.column(col_idx).is_nullable());
299
17
    return BitmapTest(row_data + schema.byte_size(), col_idx);
300
17
  }
301
302
8
  static void SetCellIsNull(const Schema& schema, uint8_t *row_data, size_t col_idx, bool is_null) {
303
8
    uint8_t *null_bitmap = row_data + schema.byte_size();
304
8
    BitmapChange(null_bitmap, col_idx, is_null);
305
8
  }
306
307
145
  static const uint8_t *cell_ptr(const Schema& schema, const uint8_t *row_data, size_t col_idx) {
308
145
    return row_data + schema.column_offset(col_idx);
309
145
  }
310
311
  static const uint8_t *nullable_cell_ptr(const Schema& schema,
312
                                          const uint8_t *row_data,
313
5
                                          size_t col_idx) {
314
5
    return is_null(schema, row_data, col_idx) ? NULL : cell_ptr(schema, row_data, col_idx);
315
5
  }
316
317
0
  static Slice CellSlice(const Schema& schema, const uint8_t *row_data, size_t col_idx) {
318
0
    const uint8_t* cell_data_ptr = cell_ptr(schema, row_data, col_idx);
319
0
    if (schema.column(col_idx).type_info()->physical_type() == BINARY) {
320
0
      return *(reinterpret_cast<const Slice*>(cell_data_ptr));
321
0
    } else {
322
0
      return Slice(cell_data_ptr, schema.column(col_idx).type_info()->size());
323
0
    }
324
0
  }
325
};
326
327
template<class ContiguousRowType>
328
class ContiguousRowCell {
329
 public:
330
  ContiguousRowCell(const ContiguousRowType* row, size_t idx)
331
85
    : row_(row), col_idx_(idx) {
332
85
  }
_ZN2yb17ContiguousRowCellINS_13ContiguousRowEEC2EPKS1_m
Line
Count
Source
331
79
    : row_(row), col_idx_(idx) {
332
79
  }
_ZN2yb17ContiguousRowCellINS_18ConstContiguousRowEEC2EPKS1_m
Line
Count
Source
331
6
    : row_(row), col_idx_(idx) {
332
6
  }
333
334
8
  const TypeInfo* typeinfo() const { return type_info(); }
335
  size_t size() const { return type_info()->size(); }
336
42
  const void* ptr() const { return row_->cell_ptr(col_idx_); }
_ZNK2yb17ContiguousRowCellINS_13ContiguousRowEE3ptrEv
Line
Count
Source
336
36
  const void* ptr() const { return row_->cell_ptr(col_idx_); }
_ZNK2yb17ContiguousRowCellINS_18ConstContiguousRowEE3ptrEv
Line
Count
Source
336
6
  const void* ptr() const { return row_->cell_ptr(col_idx_); }
337
38
  void* mutable_ptr() const { return row_->mutable_cell_ptr(col_idx_); }
338
4
  bool is_nullable() const { return row_->schema()->column(col_idx_).is_nullable(); }
339
4
  bool is_null() const { return row_->is_null(col_idx_); }
_ZNK2yb17ContiguousRowCellINS_13ContiguousRowEE7is_nullEv
Line
Count
Source
339
4
  bool is_null() const { return row_->is_null(col_idx_); }
Unexecuted instantiation: _ZNK2yb17ContiguousRowCellINS_18ConstContiguousRowEE7is_nullEv
340
  void set_null(bool is_null) const { row_->set_null(col_idx_, is_null); }
341
342
 private:
343
8
  const TypeInfo* type_info() const {
344
8
    return row_->schema()->column(col_idx_).type_info();
345
8
  }
346
347
  const ContiguousRowType* row_;
348
  size_t col_idx_;
349
};
350
351
// The row has all columns layed out in memory based on the schema.column_offset()
352
class ContiguousRow {
353
 public:
354
  typedef ContiguousRowCell<ContiguousRow> Cell;
355
356
  explicit ContiguousRow(const Schema* schema, uint8_t *row_data = NULL)
357
106
    : schema_(schema), row_data_(row_data) {
358
106
  }
359
360
56
  const Schema* schema() const {
361
56
    return schema_;
362
56
  }
363
364
2
  void Reset(uint8_t *row_data) {
365
2
    row_data_ = row_data;
366
2
  }
367
368
12
  bool is_null(size_t col_idx) const {
369
12
    return ContiguousRowHelper::is_null(*schema_, row_data_, col_idx);
370
12
  }
371
372
8
  void set_null(size_t col_idx, bool is_null) const {
373
8
    ContiguousRowHelper::SetCellIsNull(*schema_, row_data_, col_idx, is_null);
374
8
  }
375
376
123
  const uint8_t *cell_ptr(size_t col_idx) const {
377
123
    return ContiguousRowHelper::cell_ptr(*schema_, row_data_, col_idx);
378
123
  }
379
380
0
  Slice CellSlice(size_t col_idx) const {
381
0
    return ContiguousRowHelper::CellSlice(*schema_, row_data_, col_idx);
382
0
  }
383
384
62
  uint8_t *mutable_cell_ptr(size_t col_idx) const {
385
62
    return const_cast<uint8_t*>(cell_ptr(col_idx));
386
62
  }
387
388
5
  const uint8_t *nullable_cell_ptr(size_t col_idx) const {
389
5
    return ContiguousRowHelper::nullable_cell_ptr(*schema_, row_data_, col_idx);
390
5
  }
391
392
45
  Cell cell(size_t col_idx) const {
393
45
    return Cell(this, col_idx);
394
45
  }
395
396
 private:
397
  friend class ConstContiguousRow;
398
399
  const Schema* schema_;
400
  uint8_t *row_data_;
401
};
402
403
// This is the same as ContiguousRow except it refers to a const area of memory that
404
// should not be mutated.
405
class ConstContiguousRow {
406
 public:
407
  typedef ContiguousRowCell<ConstContiguousRow> Cell;
408
409
  explicit ConstContiguousRow(const ContiguousRow &row)
410
    : schema_(row.schema_),
411
0
      row_data_(row.row_data_) {
412
0
  }
413
414
  ConstContiguousRow(const Schema* schema, const void *row_data)
415
18
    : schema_(schema), row_data_(reinterpret_cast<const uint8_t *>(row_data)) {
416
18
  }
417
418
  ConstContiguousRow(const Schema* schema, const Slice& row_slice)
419
0
    : schema_(schema), row_data_(row_slice.data()) {
420
0
  }
421
422
3
  const Schema* schema() const {
423
3
    return schema_;
424
3
  }
425
426
0
  const uint8_t *row_data() const {
427
0
    return row_data_;
428
0
  }
429
430
0
  size_t row_size() const {
431
0
    return ContiguousRowHelper::row_size(*schema_);
432
0
  }
433
434
0
  bool is_null(size_t col_idx) const {
435
0
    return ContiguousRowHelper::is_null(*schema_, row_data_, col_idx);
436
0
  }
437
438
17
  const uint8_t *cell_ptr(size_t col_idx) const {
439
17
    return ContiguousRowHelper::cell_ptr(*schema_, row_data_, col_idx);
440
17
  }
441
442
0
  Slice CellSlice(size_t col_idx) const {
443
0
    return ContiguousRowHelper::CellSlice(*schema_, row_data_, col_idx);
444
0
  }
445
446
0
  const uint8_t *nullable_cell_ptr(size_t col_idx) const {
447
0
    return ContiguousRowHelper::nullable_cell_ptr(*schema_, row_data_, col_idx);
448
0
  }
449
450
6
  Cell cell(size_t col_idx) const {
451
6
    return Cell(this, col_idx);
452
6
  }
453
454
 private:
455
  const Schema* schema_;
456
  const uint8_t *row_data_;
457
};
458
459
// Delete functions from ContiguousRowCell that can mutate the cell by
460
// specializing for ConstContiguousRow.
461
template<>
462
void* ContiguousRowCell<ConstContiguousRow>::mutable_ptr() const;
463
template<>
464
void ContiguousRowCell<ConstContiguousRow>::set_null(bool null) const;
465
466
467
// Utility class for building rows corresponding to a given schema.
468
// This is used only by tests.
469
// TODO: move it into a test utility.
470
class RowBuilder {
471
 public:
472
  explicit RowBuilder(const Schema& schema)
473
    : schema_(schema),
474
      arena_(1024, 1024*1024),
475
1
      bitmap_size_(ContiguousRowHelper::null_bitmap_size(schema)) {
476
1
    Reset();
477
1
  }
478
479
  // Reset the RowBuilder so that it is ready to build
480
  // the next row.
481
  // NOTE: The previous row's data is invalidated. Even
482
  // if the previous row's data has been copied, indirected
483
  // entries such as strings may end up shared or deallocated
484
  // after Reset. So, the previous row must be fully copied
485
  // (eg using CopyRowToArena()).
486
2
  void Reset() {
487
2
    arena_.Reset();
488
2
    size_t row_size = schema_.byte_size() + bitmap_size_;
489
2
    buf_ = reinterpret_cast<uint8_t *>(arena_.AllocateBytes(row_size));
490
0
    CHECK(buf_) << "could not allocate " << row_size << " bytes for row builder";
491
2
    col_idx_ = 0;
492
2
    byte_idx_ = 0;
493
2
    ContiguousRowHelper::InitNullsBitmap(schema_, buf_, bitmap_size_);
494
2
  }
495
496
0
  void AddString(const Slice &slice) {
497
0
    CheckNextType(STRING);
498
0
    AddSlice(slice);
499
0
  }
500
501
4
  void AddString(const string &str) {
502
4
    CheckNextType(STRING);
503
4
    AddSlice(str);
504
4
  }
505
506
0
  void AddBinary(const Slice &slice) {
507
0
    CheckNextType(BINARY);
508
0
    AddSlice(slice);
509
0
  }
510
511
0
  void AddBinary(const string &str) {
512
0
    CheckNextType(BINARY);
513
0
    AddSlice(str);
514
0
  }
515
516
0
  void AddInt8(int8_t val) {
517
0
    CheckNextType(INT8);
518
0
    *reinterpret_cast<int8_t *>(&buf_[byte_idx_]) = val;
519
0
    Advance();
520
0
  }
521
522
0
  void AddUint8(uint8_t val) {
523
0
    CheckNextType(UINT8);
524
0
    *reinterpret_cast<uint8_t *>(&buf_[byte_idx_]) = val;
525
0
    Advance();
526
0
  }
527
528
0
  void AddInt16(int16_t val) {
529
0
    CheckNextType(INT16);
530
0
    *reinterpret_cast<int16_t *>(&buf_[byte_idx_]) = val;
531
0
    Advance();
532
0
  }
533
534
0
  void AddUint16(uint16_t val) {
535
0
    CheckNextType(UINT16);
536
0
    *reinterpret_cast<uint16_t *>(&buf_[byte_idx_]) = val;
537
0
    Advance();
538
0
  }
539
540
2
  void AddInt32(int32_t val) {
541
2
    CheckNextType(INT32);
542
2
    *reinterpret_cast<int32_t *>(&buf_[byte_idx_]) = val;
543
2
    Advance();
544
2
  }
545
546
2
  void AddUint32(uint32_t val) {
547
2
    CheckNextType(UINT32);
548
2
    *reinterpret_cast<uint32_t *>(&buf_[byte_idx_]) = val;
549
2
    Advance();
550
2
  }
551
552
0
  void AddInt64(int64_t val) {
553
0
    CheckNextType(INT64);
554
0
    *reinterpret_cast<int64_t *>(&buf_[byte_idx_]) = val;
555
0
    Advance();
556
0
  }
557
558
0
  void AddTimestamp(int64_t micros_utc_since_epoch) {
559
0
    CheckNextType(TIMESTAMP);
560
0
    *reinterpret_cast<int64_t *>(&buf_[byte_idx_]) = micros_utc_since_epoch;
561
0
    Advance();
562
0
  }
563
564
0
  void AddUint64(uint64_t val) {
565
0
    CheckNextType(UINT64);
566
0
    *reinterpret_cast<uint64_t *>(&buf_[byte_idx_]) = val;
567
0
    Advance();
568
0
  }
569
570
0
  void AddFloat(float val) {
571
0
    CheckNextType(FLOAT);
572
0
    *reinterpret_cast<float *>(&buf_[byte_idx_]) = val;
573
0
    Advance();
574
0
  }
575
576
0
  void AddDouble(double val) {
577
0
    CheckNextType(DOUBLE);
578
0
    *reinterpret_cast<double *>(&buf_[byte_idx_]) = val;
579
0
    Advance();
580
0
  }
581
582
0
  void AddNull() {
583
0
    CHECK(schema_.column(col_idx_).is_nullable());
584
0
    BitmapSet(buf_ + schema_.byte_size(), col_idx_);
585
0
    Advance();
586
0
  }
587
588
  // Retrieve the data slice from the current row.
589
  // The Add*() functions must have been called an appropriate
590
  // number of times such that all columns are filled in, or else
591
  // a crash will occur.
592
  //
593
  // The data slice returned by this is only valid until the next
594
  // call to Reset().
595
  // Note that the Slice may also contain pointers which refer to
596
  // other parts of the internal Arena, so even if the returned
597
  // data is copied, it is not safe to Reset() before also calling
598
  // CopyRowIndirectDataToArena.
599
2
  const Slice data() const {
600
2
    CHECK_EQ(byte_idx_, schema_.byte_size());
601
2
    return Slice(buf_, byte_idx_ + bitmap_size_);
602
2
  }
603
604
0
  const Schema& schema() const {
605
0
    return schema_;
606
0
  }
607
608
0
  ConstContiguousRow row() const {
609
0
    return ConstContiguousRow(&schema_, data());
610
0
  }
611
612
 private:
613
0
  void AddSlice(const Slice &slice) {
614
0
    Slice *ptr = reinterpret_cast<Slice *>(buf_ + byte_idx_);
615
0
    CHECK(arena_.RelocateSlice(slice, ptr)) << "could not allocate space in arena";
616
0
617
0
    Advance();
618
0
  }
619
620
4
  void AddSlice(const string &str) {
621
4
    uint8_t *in_arena = arena_.AddSlice(str);
622
0
    CHECK(in_arena) << "could not allocate space in arena";
623
624
4
    Slice *ptr = reinterpret_cast<Slice *>(buf_ + byte_idx_);
625
4
    *ptr = Slice(in_arena, str.size());
626
627
4
    Advance();
628
4
  }
629
630
8
  void CheckNextType(DataType type) {
631
8
    CHECK_EQ(schema_.column(col_idx_).type_info()->type(),
632
8
             type);
633
8
  }
634
635
8
  void Advance() {
636
8
    auto size = schema_.column(col_idx_).type_info()->size();
637
8
    byte_idx_ += size;
638
8
    col_idx_++;
639
8
  }
640
641
  const Schema schema_;
642
  Arena arena_;
643
  uint8_t *buf_;
644
645
  size_t col_idx_;
646
  size_t byte_idx_;
647
  size_t bitmap_size_;
648
649
  DISALLOW_COPY_AND_ASSIGN(RowBuilder);
650
};
651
652
} // namespace yb
653
654
#endif // YB_COMMON_ROW_H