OmniSciDB  04ee39c94c
TypedDataAccessors.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, 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 #ifndef H_TypedDataAccessors__
17 #define H_TypedDataAccessors__
18 
19 #include <cmath>
20 #include <cstring>
21 #include "Shared/DateConverters.h"
23 #include "Shared/Logger.h"
24 #include "Shared/sqltypes.h"
25 
26 namespace {
27 
28 template <typename LHT, typename RHT>
29 inline void value_truncated(const LHT& lhs, const RHT& rhs) {
30  std::ostringstream os;
31  os << "Value " << rhs << " would be truncated to "
32  << (std::is_same<LHT, uint8_t>::value || std::is_same<LHT, int8_t>::value
33  ? (int64_t)lhs
34  : lhs);
35  throw std::runtime_error(os.str());
36 };
37 
38 template <typename T>
39 inline bool is_null(const T& v, const SQLTypeInfo& t) {
40  if (std::is_floating_point<T>::value) {
41  return v == inline_fp_null_value<T>();
42  }
43  switch (t.get_logical_size()) {
44  case 1:
45  return v == inline_int_null_value<int8_t>();
46  case 2:
47  return v == inline_int_null_value<int16_t>();
48  case 4:
49  return v == inline_int_null_value<int32_t>();
50  case 8:
51  return v == inline_int_null_value<int64_t>();
52  default:
53  abort();
54  }
55 }
56 
57 template <typename LHT, typename RHT>
58 inline bool integer_setter(LHT& lhs, const RHT& rhs, const SQLTypeInfo& t) {
59  const int64_t r = is_null(rhs, t) ? inline_int_null_value<LHT>() : rhs;
60  if ((lhs = r) != r) {
61  value_truncated(lhs, r);
62  }
63  return true;
64 }
65 
66 inline int get_element_size(const SQLTypeInfo& t) {
67  if (t.is_string_array()) {
68  return sizeof(int32_t);
69  }
70  if (!t.is_array()) {
71  return t.get_size();
72  }
73  return SQLTypeInfo(t.get_subtype(),
74  t.get_dimension(),
75  t.get_scale(),
76  false,
77  t.get_compression(),
78  t.get_comp_param(),
79  kNULLT)
80  .get_size();
81 }
82 
83 inline bool is_null_string_index(const int size, const int32_t sidx) {
84  switch (size) {
85  case 1:
86  return sidx == inline_int_null_value<uint8_t>();
87  case 2:
88  return sidx == inline_int_null_value<uint16_t>();
89  case 4:
90  return sidx == inline_int_null_value<int32_t>();
91  default:
92  abort();
93  }
94 }
95 
96 inline int32_t get_string_index(void* ptr, const int size) {
97  switch (size) {
98  case 1:
99  return *(uint8_t*)ptr;
100  case 2:
101  return *(uint16_t*)ptr;
102  case 4:
103  return *(int32_t*)ptr;
104  default:
105  abort();
106  }
107 }
108 
109 inline bool set_string_index(void* ptr, const SQLTypeInfo& etype, int32_t sidx) {
110  switch (get_element_size(etype)) {
111  case 1:
112  return integer_setter(*(uint8_t*)ptr, sidx, etype);
113  break;
114  case 2:
115  return integer_setter(*(uint16_t*)ptr, sidx, etype);
116  break;
117  case 4:
118  return integer_setter(*(int32_t*)ptr, sidx, etype);
119  break;
120  default:
121  abort();
122  }
123 }
124 
125 template <typename T>
126 static void put_scalar(void* ndptr,
127  const SQLTypeInfo& etype,
128  const int esize,
129  const T oval) {
130  // round floating oval to nearest integer
131  auto rval = oval;
132  if (std::is_floating_point<T>::value) {
133  if (etype.is_integer() || etype.is_time() || etype.is_timeinterval() ||
134  etype.is_decimal()) {
135  rval = round(rval);
136  }
137  }
138  switch (etype.get_type()) {
139  case kBOOLEAN:
140  case kTIME:
141  case kTIMESTAMP:
142  case kDATE:
143  case kTINYINT:
144  case kSMALLINT:
145  case kINT:
146  case kBIGINT:
147  case kINTERVAL_DAY_TIME:
149  case kNUMERIC:
150  case kDECIMAL:
151  switch (esize) {
152  case 1:
153  integer_setter(*(int8_t*)ndptr, rval, etype);
154  break;
155  case 2:
156  integer_setter(*(int16_t*)ndptr, rval, etype);
157  break;
158  case 4:
159  integer_setter(*(int32_t*)ndptr, rval, etype);
160  break;
161  case 8:
162  integer_setter(*(int64_t*)ndptr, rval, etype);
163  break;
164  default:
165  abort();
166  }
167  break;
168  case kFLOAT:
169  *(float*)ndptr = rval;
170  break;
171  case kDOUBLE:
172  *(double*)ndptr = rval;
173  break;
174  default:
175  if (etype.is_string() && !etype.is_varlen()) {
176  set_string_index(ndptr, etype, rval);
177  } else {
178  abort();
179  }
180  break;
181  }
182 }
183 
184 inline double decimal_to_double(const SQLTypeInfo& otype, int64_t oval) {
185  return oval / pow(10, otype.get_scale());
186 }
187 
188 template <typename T>
189 inline void put_scalar(void* ndptr,
190  const SQLTypeInfo& ntype,
191  const T oval,
192  const std::string col_name,
193  const SQLTypeInfo* otype = nullptr) {
194  const auto& etype = ntype.is_array() ? SQLTypeInfo(ntype.get_subtype(),
195  ntype.get_dimension(),
196  ntype.get_scale(),
197  ntype.get_notnull(),
198  ntype.get_compression(),
199  ntype.get_comp_param(),
200  kNULLT)
201  : ntype;
202  const auto esize = get_element_size(etype);
203  const auto isnull = is_null(oval, etype);
204  if (etype.get_notnull() && isnull) {
205  throw std::runtime_error("NULL value on NOT NULL column '" + col_name + "'");
206  }
207 
208  switch (etype.get_type()) {
209  case kNUMERIC:
210  case kDECIMAL:
211  if (otype && otype->is_decimal()) {
212  put_scalar<int64_t>(ndptr,
213  etype,
214  esize,
215  isnull ? inline_int_null_value<int64_t>()
216  : convert_decimal_value_to_scale(oval, *otype, etype));
217  } else {
218  put_scalar<T>(ndptr,
219  etype,
220  esize,
221  isnull ? inline_int_null_value<int64_t>()
222  : oval * pow(10, etype.get_scale()));
223  }
224  break;
225  case kDATE:
226  // For small dates, we store in days but decode in seconds
227  // therefore we have to scale the decoded value in order to
228  // make value storable.
229  // Should be removed when we refactor code to use DateConverterFactory
230  // from TargetValueConverterFactories so that we would
231  // have everything in one place.
232  if (etype.is_date_in_days()) {
233  put_scalar<T>(ndptr,
234  etype,
235  get_element_size(etype),
236  isnull ? inline_int_null_value<int64_t>()
238  static_cast<int64_t>(oval)));
239  } else {
240  put_scalar<T>(ndptr, etype, get_element_size(etype), oval);
241  }
242  break;
243  default:
244  if (otype && otype->is_decimal()) {
245  put_scalar<double>(ndptr, etype, decimal_to_double(*otype, oval), col_name);
246  } else {
247  put_scalar<T>(ndptr, etype, get_element_size(etype), oval);
248  }
249  break;
250  }
251 }
252 
253 inline void put_null(void* ndptr, const SQLTypeInfo& ntype, const std::string col_name) {
254  if (ntype.get_notnull()) {
255  throw std::runtime_error("NULL value on NOT NULL column '" + col_name + "'");
256  }
257 
258  switch (ntype.get_type()) {
259  case kBOOLEAN:
260  case kTINYINT:
261  case kSMALLINT:
262  case kINT:
263  case kBIGINT:
264  case kTIME:
265  case kTIMESTAMP:
266  case kDATE:
267  case kINTERVAL_DAY_TIME:
269  case kNUMERIC:
270  case kDECIMAL:
271  switch (ntype.get_size()) {
272  case 1:
273  *(int8_t*)ndptr = inline_int_null_value<int8_t>();
274  break;
275  case 2:
276  *(int16_t*)ndptr = inline_int_null_value<int16_t>();
277  break;
278  case 4:
279  *(int32_t*)ndptr = inline_int_null_value<int32_t>();
280  break;
281  case 8:
282  *(int64_t*)ndptr = inline_int_null_value<int64_t>();
283  break;
284  default:
285  abort();
286  }
287  break;
288  case kFLOAT:
289  *(float*)ndptr = inline_fp_null_value<float>();
290  break;
291  case kDOUBLE:
292  *(double*)ndptr = inline_fp_null_value<double>();
293  break;
294  default:
297  CHECK(false);
298  }
299 }
300 
301 inline void put_null_array(void* ndptr,
302  const SQLTypeInfo& ntype,
303  const std::string col_name) {
304  if (ntype.get_notnull()) {
305  throw std::runtime_error("NULL value on NOT NULL column '" + col_name + "'");
306  }
307 
308  switch (ntype.get_type()) {
309  case kBOOLEAN:
310  case kTINYINT:
311  case kSMALLINT:
312  case kINT:
313  case kBIGINT:
314  case kTIME:
315  case kTIMESTAMP:
316  case kDATE:
317  case kINTERVAL_DAY_TIME:
319  case kNUMERIC:
320  case kDECIMAL:
321  switch (ntype.get_size()) {
322  case 1:
323  *(int8_t*)ndptr = inline_int_null_array_value<int8_t>();
324  break;
325  case 2:
326  *(int16_t*)ndptr = inline_int_null_array_value<int16_t>();
327  break;
328  case 4:
329  *(int32_t*)ndptr = inline_int_null_array_value<int32_t>();
330  break;
331  case 8:
332  *(int64_t*)ndptr = inline_int_null_array_value<int64_t>();
333  break;
334  default:
335  abort();
336  }
337  break;
338  case kFLOAT:
339  *(float*)ndptr = inline_fp_null_array_value<float>();
340  break;
341  case kDOUBLE:
342  *(double*)ndptr = inline_fp_null_array_value<double>();
343  break;
344  default:
347  CHECK(false);
348  }
349 }
350 
351 template <typename T>
352 inline bool get_scalar(void* ndptr, const SQLTypeInfo& ntype, T& v) {
353  switch (ntype.get_type()) {
354  case kBOOLEAN:
355  case kTINYINT:
356  case kSMALLINT:
357  case kINT:
358  case kBIGINT:
359  case kTIME:
360  case kTIMESTAMP:
361  case kDATE:
362  case kINTERVAL_DAY_TIME:
364  case kNUMERIC:
365  case kDECIMAL:
366  switch (ntype.get_size()) {
367  case 1:
368  return inline_int_null_value<int8_t>() == (v = *(int8_t*)ndptr);
369  case 2:
370  return inline_int_null_value<int16_t>() == (v = *(int16_t*)ndptr);
371  case 4:
372  return inline_int_null_value<int32_t>() == (v = *(int32_t*)ndptr);
373  case 8:
374  return inline_int_null_value<int64_t>() == (v = *(int64_t*)ndptr);
375  break;
376  default:
377  abort();
378  }
379  break;
380  case kFLOAT:
381  return inline_fp_null_value<float>() == (v = *(float*)ndptr);
382  case kDOUBLE:
383  return inline_fp_null_value<double>() == (v = *(double*)ndptr);
384  case kTEXT:
385  v = get_string_index(ndptr, ntype.get_size());
386  return is_null_string_index(ntype.get_size(), v);
387  default:
388  abort();
389  }
390 }
391 
393  public:
394  template <typename TYPE_INFO, typename VAL>
395  auto operator()(TYPE_INFO const& ti, VAL const&) const {
396  using FloatOrIntSelector =
397  typename std::conditional<std::is_floating_point<std::decay_t<VAL> >::value,
398  FPSelector,
400  return get_null_sentinel_for_type(ti, FloatOrIntSelector());
401  }
402 
403  private:
404  struct IntSelector {};
405  struct FPSelector {};
406 
407  template <typename TYPE_INFO>
408  int64_t get_null_sentinel_for_type(TYPE_INFO const& ti, IntSelector const&) const {
410  }
411 
412  template <typename TYPE_INFO>
413  double get_null_sentinel_for_type(TYPE_INFO const& ti, FPSelector const&) const {
414  return inline_fp_null_val(ti);
415  }
416 };
417 
418 template <typename T>
419 inline void set_minmax(T& min, T& max, T const val) {
420  if (val < min) {
421  min = val;
422  }
423  if (val > max) {
424  max = val;
425  }
426 }
427 
428 template <typename T>
429 inline void set_minmax(T& min, T& max, int8_t& null_flag, T const val, T null_sentinel) {
430  if (val == null_sentinel) {
431  null_flag |= true;
432  } else {
433  if (val < min) {
434  min = val;
435  }
436  if (val > max) {
437  max = val;
438  }
439  }
440 }
441 
442 template <typename TYPE_INFO,
443  typename T,
444  typename SENTINEL_SUPPLIER = NullSentinelSupplier>
445 inline void tabulate_metadata(TYPE_INFO const& ti,
446  T& min,
447  T& max,
448  int8_t& null_flag,
449  T const val,
450  SENTINEL_SUPPLIER s = SENTINEL_SUPPLIER()) {
451  if (ti.get_notnull()) {
452  set_minmax(min, max, val);
453  } else {
454  set_minmax(min, max, null_flag, val, s(ti, val));
455  }
456 }
457 
458 } // namespace
459 #endif
bool is_string_array() const
Definition: sqltypes.h:451
bool is_time() const
Definition: sqltypes.h:456
HOST DEVICE int get_size() const
Definition: sqltypes.h:333
HOST DEVICE int get_dimension() const
Definition: sqltypes.h:325
Definition: sqltypes.h:51
double decimal_to_double(const SQLTypeInfo &otype, int64_t oval)
HOST DEVICE bool get_notnull() const
Definition: sqltypes.h:330
bool is_null_string_index(const int size, const int32_t sidx)
void value_truncated(const LHT &lhs, const RHT &rhs)
HOST DEVICE int get_scale() const
Definition: sqltypes.h:328
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:323
bool is_varlen() const
Definition: sqltypes.h:464
void put_scalar(void *ndptr, const SQLTypeInfo &ntype, const T oval, const std::string col_name, const SQLTypeInfo *otype=nullptr)
SQLTypeInfo get_logical_type_info(const SQLTypeInfo &type_info)
Definition: sqltypes.h:840
int64_t get_null_sentinel_for_type(TYPE_INFO const &ti, IntSelector const &) const
Constants for Builtin SQL Types supported by MapD.
auto operator()(TYPE_INFO const &ti, VAL const &) const
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:331
double inline_fp_null_val(const SQL_TYPE_INFO &ti)
bool is_array() const
Definition: sqltypes.h:458
bool is_timeinterval() const
Definition: sqltypes.h:461
bool is_integer() const
Definition: sqltypes.h:452
T v(const TargetValue &r)
bool get_scalar(void *ndptr, const SQLTypeInfo &ntype, T &v)
bool is_decimal() const
Definition: sqltypes.h:453
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:324
void put_null_array(void *ndptr, const SQLTypeInfo &ntype, const std::string col_name)
void set_minmax(T &min, T &max, int8_t &null_flag, T const val, T null_sentinel)
SQLTypeInfoCore< ArrayContextTypeSizer, ExecutorTypePackaging, DateTimeFacilities > SQLTypeInfo
Definition: sqltypes.h:823
double get_null_sentinel_for_type(TYPE_INFO const &ti, FPSelector const &) const
void put_null(void *ndptr, const SQLTypeInfo &ntype, const std::string col_name)
void tabulate_metadata(TYPE_INFO const &ti, T &min, T &max, int8_t &null_flag, T const val, SENTINEL_SUPPLIER s=SENTINEL_SUPPLIER())
Definition: sqltypes.h:54
Definition: sqltypes.h:55
bool is_null(const T &v, const SQLTypeInfo &t)
int64_t convert_decimal_value_to_scale(const int64_t decimal_value, const SQLTypeInfo &type_info, const SQLTypeInfo &new_type_info)
Definition: Datum.cpp:284
constexpr double inline_fp_null_array_value< double >()
constexpr float inline_fp_null_value< float >()
constexpr double inline_fp_null_value< double >()
int get_logical_size() const
Definition: sqltypes.h:334
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:332
bool set_string_index(void *ptr, const SQLTypeInfo &etype, int32_t sidx)
bool integer_setter(LHT &lhs, const RHT &rhs, const SQLTypeInfo &t)
#define CHECK(condition)
Definition: Logger.h:187
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
int64_t get_epoch_days_from_seconds(const int64_t seconds)
Definition: sqltypes.h:47
int32_t get_string_index(void *ptr, const int size)
bool is_string() const
Definition: sqltypes.h:450
constexpr float inline_fp_null_array_value< float >()