OmniSciDB  cde582ebc3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FixedLengthArrayNoneEncoder.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
23 #ifndef FIXED_LENGTH_ARRAY_NONE_ENCODER_H
24 #define FIXED_LENGTH_ARRAY_NONE_ENCODER_H
25 
26 #include "Logger/Logger.h"
27 
28 #include <cassert>
29 #include <cstring>
30 #include <memory>
31 #include <mutex>
32 #include <string>
33 #include <vector>
34 #include "AbstractBuffer.h"
35 #include "ChunkMetadata.h"
36 #include "Encoder.h"
37 
39 
41  public:
43  : Encoder(buffer), has_nulls(false), initialized(false), array_size(as) {}
44 
45  size_t getNumElemsForBytesEncodedDataAtIndices(const int8_t* index_data,
46  const std::vector<size_t>& selected_idx,
47  const size_t byte_limit) override {
48  size_t data_size = selected_idx.size() * array_size;
49  if (data_size > byte_limit) {
50  data_size = byte_limit;
51  }
52  return data_size / array_size;
53  }
54 
55  size_t getNumElemsForBytesInsertData(const std::vector<ArrayDatum>* srcData,
56  const int start_idx,
57  const size_t numAppendElems,
58  const size_t byteLimit,
59  const bool replicating = false) {
60  size_t dataSize = numAppendElems * array_size;
61  if (dataSize > byteLimit) {
62  dataSize = byteLimit;
63  }
64  return dataSize / array_size;
65  }
66 
67  std::shared_ptr<ChunkMetadata> appendEncodedDataAtIndices(
68  const int8_t* index_data,
69  int8_t* data,
70  const std::vector<size_t>& selected_idx) override {
71  std::vector<ArrayDatum> data_subset;
72  data_subset.reserve(selected_idx.size());
73  for (const auto& index : selected_idx) {
74  auto current_data = data + array_size * (index);
75  data_subset.emplace_back(ArrayDatum(array_size,
76  current_data,
77  is_null_ignore_not_null(current_data),
78  DoNothingDeleter{}));
79  }
80  return appendData(&data_subset, 0, selected_idx.size(), false);
81  }
82 
83  std::shared_ptr<ChunkMetadata> appendEncodedData(const int8_t* index_data,
84  int8_t* data,
85  const size_t start_idx,
86  const size_t num_elements) override {
87  std::vector<ArrayDatum> data_subset;
88  data_subset.reserve(num_elements);
89  for (size_t count = 0; count < num_elements; ++count) {
90  auto current_data = data + array_size * (start_idx + count);
91  data_subset.emplace_back(
92  ArrayDatum(array_size, current_data, false, DoNothingDeleter{}));
93  }
94  return appendData(&data_subset, 0, num_elements, false);
95  }
96 
97  std::shared_ptr<ChunkMetadata> appendData(int8_t*& src_data,
98  const size_t num_elems_to_append,
99  const SQLTypeInfo& ti,
100  const bool replicating = false,
101  const int64_t offset = -1) override {
102  UNREACHABLE(); // should never be called for arrays
103  return nullptr;
104  }
105 
106  std::shared_ptr<ChunkMetadata> appendData(const std::vector<ArrayDatum>* srcData,
107  const int start_idx,
108  const size_t numAppendElems,
109  const bool replicating = false) {
110  // Todo: The reserve call was changed to take into account the existing data size,
111  // but in other encoders (like ArrayNoneEncoder) we only reserve the append size,
112  // which will be a no-op likely after the first append on a chunk. This probably
113  // won't matter for disk writes as we just have static (default 2MB) page sizes, but
114  // could be an issue for temporary in-memory tables, as buffers for multi-column
115  // imports will likely need to be repeatedly migrated to grow them if they are
116  // "landlocked" amidst other buffers. We should follow-up with work to call reserve
117  // properly, accounting for both the new append size and existing size, for that
118  // reason and just for overall semantic correctness.
119 
120  const size_t existing_data_size = num_elems_ * array_size;
121  const size_t append_data_size = array_size * numAppendElems;
122  buffer_->reserve(existing_data_size + append_data_size);
123  std::vector<int8_t> append_buffer(append_data_size);
124  int8_t* append_ptr = append_buffer.data();
125 
126  // There was some worry about the change implemented to write the append data to an
127  // intermediate buffer, but testing on import and ctas of 20M points, we never append
128  // more than 1.6MB and 1MB of data at a time, respectively, so at least for fixed
129  // length types this should not be an issue (varlen types, which can be massive even
130  // for a single field/row, are a different story however)
131 
132  if (replicating) {
133  const size_t len = (*srcData)[0].length;
134  CHECK_EQ(len, array_size);
135  const int8_t* replicated_ptr = (*srcData)[0].pointer;
136  for (size_t i = 0; i < numAppendElems; ++i) {
137  std::memcpy(append_ptr + i * array_size, replicated_ptr, array_size);
138  }
139  } else {
140  for (size_t i = 0; i < numAppendElems; ++i) {
141  // Length of the appended array should be equal to the fixed length,
142  // all others should have been discarded, assert if something slips through
143  const size_t source_idx = start_idx + i;
144  const size_t len = (*srcData)[source_idx].length;
145  CHECK_EQ(len, array_size);
146  // NULL arrays have been filled with subtype's NULL sentinels,
147  // should be appended as regular data, same size
148  std::memcpy(
149  append_ptr + i * array_size, (*srcData)[source_idx].pointer, array_size);
150  }
151  }
152 
153  buffer_->append(append_ptr, append_data_size);
154 
155  if (replicating) {
156  updateStats(srcData, 0, 1);
157  } else {
158  updateStats(srcData, start_idx, numAppendElems);
159  }
160 
161  // make sure buffer_ is flushed even if no new data is appended to it
162  // (e.g. empty strings) because the metadata needs to be flushed.
163  if (!buffer_->isDirty()) {
164  buffer_->setDirty();
165  }
166 
167  num_elems_ += numAppendElems;
168  auto chunk_metadata = std::make_shared<ChunkMetadata>();
169  getMetadata(chunk_metadata);
170  return chunk_metadata;
171  }
172 
173  void getMetadata(const std::shared_ptr<ChunkMetadata>& chunkMetadata) override {
174  Encoder::getMetadata(chunkMetadata); // call on parent class
175  chunkMetadata->fillChunkStats(elem_min, elem_max, has_nulls);
176  }
177 
178  // Only called from the executor for synthesized meta-information.
179  std::shared_ptr<ChunkMetadata> getMetadata(const SQLTypeInfo& ti) override {
180  auto chunk_metadata = std::make_shared<ChunkMetadata>(
181  ti, 0, 0, ChunkStats{elem_min, elem_max, has_nulls});
182  return chunk_metadata;
183  }
184 
185  void updateStats(const int64_t, const bool) override { CHECK(false); }
186 
187  void updateStats(const double, const bool) override { CHECK(false); }
188 
189  void reduceStats(const Encoder&) override { CHECK(false); }
190 
191  void updateStats(const int8_t* const src_data, const size_t num_elements) override {
192  UNREACHABLE();
193  }
194 
195  void updateStats(const std::vector<std::string>* const src_data,
196  const size_t start_idx,
197  const size_t num_elements) override {
198  UNREACHABLE();
199  }
200 
201  void updateStats(const std::vector<ArrayDatum>* const src_data,
202  const size_t start_idx,
203  const size_t num_elements) override {
204  for (size_t n = start_idx; n < start_idx + num_elements; n++) {
205  update_elem_stats((*src_data)[n]);
206  }
207  }
208 
209  void writeMetadata(FILE* f) override {
210  // assumes pointer is already in right place
211  fwrite((int8_t*)&num_elems_, sizeof(size_t), 1, f);
212  fwrite((int8_t*)&elem_min, sizeof(Datum), 1, f);
213  fwrite((int8_t*)&elem_max, sizeof(Datum), 1, f);
214  fwrite((int8_t*)&has_nulls, sizeof(bool), 1, f);
215  fwrite((int8_t*)&initialized, sizeof(bool), 1, f);
216  }
217 
218  void readMetadata(FILE* f) override {
219  // assumes pointer is already in right place
220  fread((int8_t*)&num_elems_, sizeof(size_t), 1, f);
221  fread((int8_t*)&elem_min, sizeof(Datum), 1, f);
222  fread((int8_t*)&elem_max, sizeof(Datum), 1, f);
223  fread((int8_t*)&has_nulls, sizeof(bool), 1, f);
224  fread((int8_t*)&initialized, sizeof(bool), 1, f);
225  }
226 
227  void copyMetadata(const Encoder* copyFromEncoder) override {
228  num_elems_ = copyFromEncoder->getNumElems();
229  auto array_encoder =
230  dynamic_cast<const FixedLengthArrayNoneEncoder*>(copyFromEncoder);
231  elem_min = array_encoder->elem_min;
232  elem_max = array_encoder->elem_max;
233  has_nulls = array_encoder->has_nulls;
234  initialized = array_encoder->initialized;
235  }
236 
237  void updateMetadata(int8_t* array) {
239  }
240 
241  static bool is_null_ignore_not_null(const SQLTypeInfo& type, int8_t* array) {
242  switch (type.get_subtype()) {
243  case kBOOLEAN: {
244  return (array[0] == NULL_ARRAY_BOOLEAN);
245  }
246  case kINT: {
247  const int32_t* int_array = (int32_t*)array;
248  return (int_array[0] == NULL_ARRAY_INT);
249  }
250  case kSMALLINT: {
251  const int16_t* smallint_array = (int16_t*)array;
252  return (smallint_array[0] == NULL_ARRAY_SMALLINT);
253  }
254  case kTINYINT: {
255  const int8_t* tinyint_array = (int8_t*)array;
256  return (tinyint_array[0] == NULL_ARRAY_TINYINT);
257  }
258  case kBIGINT:
259  case kNUMERIC:
260  case kDECIMAL: {
261  const int64_t* bigint_array = (int64_t*)array;
262  return (bigint_array[0] == NULL_ARRAY_BIGINT);
263  }
264  case kFLOAT: {
265  const float* flt_array = (float*)array;
266  return (flt_array[0] == NULL_ARRAY_FLOAT);
267  }
268  case kDOUBLE: {
269  const double* dbl_array = (double*)array;
270  return (dbl_array[0] == NULL_ARRAY_DOUBLE);
271  }
272  case kTIME:
273  case kTIMESTAMP:
274  case kDATE: {
275  const int64_t* tm_array = reinterpret_cast<int64_t*>(array);
276  return (tm_array[0] == NULL_ARRAY_BIGINT);
277  }
278  case kCHAR:
279  case kVARCHAR:
280  case kTEXT: {
282  const int32_t* int_array = (int32_t*)array;
283  return (int_array[0] == NULL_ARRAY_INT);
284  }
285  default:
286  UNREACHABLE();
287  }
288  return false;
289  }
290 
291  static bool is_null(const SQLTypeInfo& type, int8_t* array) {
292  if (type.get_notnull()) {
293  return false;
294  }
295  return is_null_ignore_not_null(type, array);
296  }
297 
298  bool resetChunkStats(const ChunkStats& stats) override {
299  auto elem_type = buffer_->getSqlType().get_elem_type();
300  if (initialized && DatumEqual(elem_min, stats.min, elem_type) &&
301  DatumEqual(elem_max, stats.max, elem_type) && has_nulls == stats.has_nulls) {
302  return false;
303  }
304  elem_min = stats.min;
305  elem_max = stats.max;
306  has_nulls = stats.has_nulls;
307  return true;
308  }
309 
310  void resetChunkStats() override {
311  has_nulls = false;
312  initialized = false;
313  }
314 
317  bool has_nulls;
319 
320  private:
321  std::mutex EncoderMutex_;
322  std::mutex print_mutex_;
323  size_t array_size;
324 
325  bool is_null(int8_t* array) { return is_null(buffer_->getSqlType(), array); }
326 
327  bool is_null_ignore_not_null(int8_t* array) {
328  return is_null_ignore_not_null(buffer_->getSqlType(), array);
329  }
330 
331  void update_elem_stats(const ArrayDatum& array) {
332  if (array.is_null) {
333  has_nulls = true;
334  }
335  switch (buffer_->getSqlType().get_subtype()) {
336  case kBOOLEAN: {
337  if (!initialized) {
338  elem_min.boolval = true;
339  elem_max.boolval = false;
340  }
341  if (array.is_null) {
342  break;
343  }
344  const int8_t* bool_array = array.pointer;
345  for (size_t i = 0; i < array.length / sizeof(bool); i++) {
346  if (bool_array[i] == NULL_BOOLEAN) {
347  has_nulls = true;
348  } else if (initialized) {
349  elem_min.boolval = std::min(elem_min.boolval, bool_array[i]);
350  elem_max.boolval = std::max(elem_max.boolval, bool_array[i]);
351  } else {
352  elem_min.boolval = bool_array[i];
353  elem_max.boolval = bool_array[i];
354  initialized = true;
355  }
356  }
357  break;
358  }
359  case kINT: {
360  if (!initialized) {
361  elem_min.intval = 1;
362  elem_max.intval = 0;
363  }
364  if (array.is_null) {
365  break;
366  }
367  const int32_t* int_array = (int32_t*)array.pointer;
368  for (size_t i = 0; i < array.length / sizeof(int32_t); i++) {
369  if (int_array[i] == NULL_INT) {
370  has_nulls = true;
371  } else if (initialized) {
372  elem_min.intval = std::min(elem_min.intval, int_array[i]);
373  elem_max.intval = std::max(elem_max.intval, int_array[i]);
374  } else {
375  elem_min.intval = int_array[i];
376  elem_max.intval = int_array[i];
377  initialized = true;
378  }
379  }
380  break;
381  }
382  case kSMALLINT: {
383  if (!initialized) {
384  elem_min.smallintval = 1;
385  elem_max.smallintval = 0;
386  }
387  if (array.is_null) {
388  break;
389  }
390  const int16_t* smallint_array = (int16_t*)array.pointer;
391  for (size_t i = 0; i < array.length / sizeof(int16_t); i++) {
392  if (smallint_array[i] == NULL_SMALLINT) {
393  has_nulls = true;
394  } else if (initialized) {
395  elem_min.smallintval = std::min(elem_min.smallintval, smallint_array[i]);
396  elem_max.smallintval = std::max(elem_max.smallintval, smallint_array[i]);
397  } else {
398  elem_min.smallintval = smallint_array[i];
399  elem_max.smallintval = smallint_array[i];
400  initialized = true;
401  }
402  }
403  break;
404  }
405  case kTINYINT: {
406  if (!initialized) {
407  elem_min.tinyintval = 1;
408  elem_max.tinyintval = 0;
409  }
410  if (array.is_null) {
411  break;
412  }
413  const int8_t* tinyint_array = (int8_t*)array.pointer;
414  for (size_t i = 0; i < array.length / sizeof(int8_t); i++) {
415  if (tinyint_array[i] == NULL_TINYINT) {
416  has_nulls = true;
417  } else if (initialized) {
418  elem_min.tinyintval = std::min(elem_min.tinyintval, tinyint_array[i]);
419  elem_max.tinyintval = std::max(elem_max.tinyintval, tinyint_array[i]);
420  } else {
421  elem_min.tinyintval = tinyint_array[i];
422  elem_max.tinyintval = tinyint_array[i];
423  initialized = true;
424  }
425  }
426  break;
427  }
428  case kBIGINT:
429  case kNUMERIC:
430  case kDECIMAL: {
431  if (!initialized) {
432  elem_min.bigintval = 1;
433  elem_max.bigintval = 0;
434  }
435  if (array.is_null) {
436  break;
437  }
438  const int64_t* bigint_array = (int64_t*)array.pointer;
439  for (size_t i = 0; i < array.length / sizeof(int64_t); i++) {
440  if (bigint_array[i] == NULL_BIGINT) {
441  has_nulls = true;
442  } else if (initialized) {
443  decimal_overflow_validator_.validate(bigint_array[i]);
444  elem_min.bigintval = std::min(elem_min.bigintval, bigint_array[i]);
445  elem_max.bigintval = std::max(elem_max.bigintval, bigint_array[i]);
446  } else {
447  decimal_overflow_validator_.validate(bigint_array[i]);
448  elem_min.bigintval = bigint_array[i];
449  elem_max.bigintval = bigint_array[i];
450  initialized = true;
451  }
452  }
453  break;
454  }
455  case kFLOAT: {
456  if (!initialized) {
457  elem_min.floatval = 1.0;
458  elem_max.floatval = 0.0;
459  }
460  if (array.is_null) {
461  break;
462  }
463  const float* flt_array = (float*)array.pointer;
464  for (size_t i = 0; i < array.length / sizeof(float); i++) {
465  if (flt_array[i] == NULL_FLOAT) {
466  has_nulls = true;
467  } else if (initialized) {
468  elem_min.floatval = std::min(elem_min.floatval, flt_array[i]);
469  elem_max.floatval = std::max(elem_max.floatval, flt_array[i]);
470  } else {
471  elem_min.floatval = flt_array[i];
472  elem_max.floatval = flt_array[i];
473  initialized = true;
474  }
475  }
476  break;
477  }
478  case kDOUBLE: {
479  if (!initialized) {
480  elem_min.doubleval = 1.0;
481  elem_max.doubleval = 0.0;
482  }
483  if (array.is_null) {
484  break;
485  }
486  const double* dbl_array = (double*)array.pointer;
487  for (size_t i = 0; i < array.length / sizeof(double); i++) {
488  if (dbl_array[i] == NULL_DOUBLE) {
489  has_nulls = true;
490  } else if (initialized) {
491  elem_min.doubleval = std::min(elem_min.doubleval, dbl_array[i]);
492  elem_max.doubleval = std::max(elem_max.doubleval, dbl_array[i]);
493  } else {
494  elem_min.doubleval = dbl_array[i];
495  elem_max.doubleval = dbl_array[i];
496  initialized = true;
497  }
498  }
499  break;
500  }
501  case kTIME:
502  case kTIMESTAMP:
503  case kDATE: {
504  if (!initialized) {
505  elem_min.bigintval = 1;
506  elem_max.bigintval = 0;
507  }
508  if (array.is_null) {
509  break;
510  }
511  const int64_t* tm_array = reinterpret_cast<int64_t*>(array.pointer);
512  for (size_t i = 0; i < array.length / sizeof(int64_t); i++) {
513  if (tm_array[i] == NULL_BIGINT) {
514  has_nulls = true;
515  } else if (initialized) {
516  elem_min.bigintval = std::min(elem_min.bigintval, tm_array[i]);
517  elem_max.bigintval = std::max(elem_max.bigintval, tm_array[i]);
518  } else {
519  elem_min.bigintval = tm_array[i];
520  elem_max.bigintval = tm_array[i];
521  initialized = true;
522  }
523  }
524  break;
525  }
526  case kCHAR:
527  case kVARCHAR:
528  case kTEXT: {
530  if (!initialized) {
531  elem_min.intval = 1;
532  elem_max.intval = 0;
533  }
534  if (array.is_null) {
535  break;
536  }
537  const int32_t* int_array = (int32_t*)array.pointer;
538  for (size_t i = 0; i < array.length / sizeof(int32_t); i++) {
539  if (int_array[i] == NULL_INT) {
540  has_nulls = true;
541  } else if (initialized) {
542  elem_min.intval = std::min(elem_min.intval, int_array[i]);
543  elem_max.intval = std::max(elem_max.intval, int_array[i]);
544  } else {
545  elem_min.intval = int_array[i];
546  elem_max.intval = int_array[i];
547  initialized = true;
548  }
549  }
550  break;
551  }
552  default:
553  UNREACHABLE();
554  }
555  };
556 
557 }; // class FixedLengthArrayNoneEncoder
558 
559 #endif // FIXED_LENGTH_ARRAY_NONE_ENCODER_H
int8_t tinyintval
Definition: sqltypes.h:212
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:330
#define CHECK_EQ(x, y)
Definition: Logger.h:230
#define NULL_DOUBLE
void updateStats(const int8_t *const src_data, const size_t num_elements) override
size_t num_elems_
Definition: Encoder.h:288
Definition: sqltypes.h:49
#define NULL_ARRAY_INT
#define NULL_FLOAT
DecimalOverflowValidator decimal_overflow_validator_
Definition: Encoder.h:292
#define NULL_BIGINT
std::shared_ptr< ChunkMetadata > appendEncodedData(const int8_t *index_data, int8_t *data, const size_t start_idx, const size_t num_elements) override
#define NULL_ARRAY_SMALLINT
int8_t boolval
Definition: sqltypes.h:211
#define UNREACHABLE()
Definition: Logger.h:266
bool has_nulls
Definition: ChunkMetadata.h:30
#define NULL_ARRAY_TINYINT
int32_t intval
Definition: sqltypes.h:214
constexpr double f
Definition: Utm.h:31
#define NULL_INT
virtual void getMetadata(const std::shared_ptr< ChunkMetadata > &chunkMetadata)
Definition: Encoder.cpp:227
void updateStats(const double, const bool) override
std::conditional_t< is_cuda_compiler(), DeviceArrayDatum, HostArrayDatum > ArrayDatum
Definition: sqltypes.h:208
float floatval
Definition: sqltypes.h:216
FixedLengthArrayNoneEncoder(AbstractBuffer *buffer, size_t as)
void getMetadata(const std::shared_ptr< ChunkMetadata > &chunkMetadata) override
std::shared_ptr< ChunkMetadata > appendData(int8_t *&src_data, const size_t num_elems_to_append, const SQLTypeInfo &ti, const bool replicating=false, const int64_t offset=-1) override
Data_Namespace::AbstractBuffer * buffer_
Definition: Encoder.h:290
std::shared_ptr< ChunkMetadata > getMetadata(const SQLTypeInfo &ti) override
bool DatumEqual(const Datum a, const Datum b, const SQLTypeInfo &ti)
Definition: Datum.cpp:342
size_t getNumElemsForBytesEncodedDataAtIndices(const int8_t *index_data, const std::vector< size_t > &selected_idx, const size_t byte_limit) override
void copyMetadata(const Encoder *copyFromEncoder) override
int64_t bigintval
Definition: sqltypes.h:215
size_t getNumElems() const
Definition: Encoder.h:284
#define NULL_ARRAY_FLOAT
std::shared_ptr< ChunkMetadata > appendEncodedDataAtIndices(const int8_t *index_data, int8_t *data, const std::vector< size_t > &selected_idx) override
int16_t smallintval
Definition: sqltypes.h:213
An AbstractBuffer is a unit of data management for a data manager.
#define NULL_BOOLEAN
Definition: sqltypes.h:52
Definition: sqltypes.h:53
void updateStats(const std::vector< std::string > *const src_data, const size_t start_idx, const size_t num_elements) override
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:337
Definition: sqltypes.h:41
virtual void append(int8_t *src, const size_t num_bytes, const MemoryLevel src_buffer_type=CPU_LEVEL, const int device_id=-1)=0
SQLTypeInfo getSqlType() const
#define NULL_TINYINT
#define NULL_ARRAY_DOUBLE
void update_elem_stats(const ArrayDatum &array)
void reduceStats(const Encoder &) override
bool g_enable_watchdog false
Definition: Execute.cpp:79
#define CHECK(condition)
Definition: Logger.h:222
void updateStats(const int64_t, const bool) override
#define NULL_SMALLINT
#define NULL_ARRAY_BIGINT
static bool is_null(const SQLTypeInfo &type, int8_t *array)
Definition: sqltypes.h:45
void updateStats(const std::vector< ArrayDatum > *const src_data, const size_t start_idx, const size_t num_elements) override
#define NULL_ARRAY_BOOLEAN
constexpr double n
Definition: Utm.h:38
HOST DEVICE bool get_notnull() const
Definition: sqltypes.h:336
static bool is_null_ignore_not_null(const SQLTypeInfo &type, int8_t *array)
size_t getNumElemsForBytesInsertData(const std::vector< ArrayDatum > *srcData, const int start_idx, const size_t numAppendElems, const size_t byteLimit, const bool replicating=false)
void validate(T value) const
Definition: Encoder.h:54
SQLTypeInfo get_elem_type() const
Definition: sqltypes.h:865
virtual void reserve(size_t num_bytes)=0
double doubleval
Definition: sqltypes.h:217
std::shared_ptr< ChunkMetadata > appendData(const std::vector< ArrayDatum > *srcData, const int start_idx, const size_t numAppendElems, const bool replicating=false)
bool resetChunkStats(const ChunkStats &stats) override
: Reset chunk level stats (min, max, nulls) using new values from the argument.