OmniSciDB  06b3bd477c
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Datum.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 OmniSci, 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 
25 #include <cassert>
26 #include <cstdio>
27 #include <cstdlib>
28 #include <stdexcept>
29 #include <string>
30 
31 #include "DateConverters.h"
32 #include "Logger.h"
34 #include "StringTransform.h"
35 #include "TimeGM.h"
36 #include "misc.h"
37 #include "sqltypes.h"
38 
39 std::string SQLTypeInfo::type_name[kSQLTYPE_LAST] = {"NULL",
40  "BOOLEAN",
41  "CHAR",
42  "VARCHAR",
43  "NUMERIC",
44  "DECIMAL",
45  "INTEGER",
46  "SMALLINT",
47  "FLOAT",
48  "DOUBLE",
49  "TIME",
50  "TIMESTAMP",
51  "BIGINT",
52  "TEXT",
53  "DATE",
54  "ARRAY",
55  "INTERVAL_DAY_TIME",
56  "INTERVAL_YEAR_MONTH",
57  "POINT",
58  "LINESTRING",
59  "POLYGON",
60  "MULTIPOLYGON",
61  "TINYINT",
62  "GEOMETRY",
63  "GEOGRAPHY",
64  "EVAL_CONTEXT_TYPE",
65  "VOID",
66  "CURSOR",
67  "COLUMN"};
69  {"NONE", "FIXED", "RL", "DIFF", "DICT", "SPARSE", "COMPRESSED", "DAYS"};
70 
71 int64_t parse_numeric(const std::string_view s, SQLTypeInfo& ti) {
72  assert(s.length() <= 20);
73  size_t dot = s.find_first_of('.', 0);
74  std::string before_dot;
75  std::string after_dot;
76  if (dot != std::string::npos) {
77  // make .99 as 0.99, or std::stoll below throws exception 'std::invalid_argument'
78  before_dot = (0 == dot) ? "0" : s.substr(0, dot);
79  after_dot = s.substr(dot + 1);
80  } else {
81  before_dot = s;
82  after_dot = "0";
83  }
84  const bool is_negative = before_dot.find_first_of('-', 0) != std::string::npos;
85  const int64_t sign = is_negative ? -1 : 1;
86  int64_t result;
87  result = std::abs(std::stoll(before_dot));
88  int64_t fraction = 0;
89  const size_t before_dot_digits = before_dot.length() - (is_negative ? 1 : 0);
90  if (!after_dot.empty()) {
91  fraction = std::stoll(after_dot);
92  }
93  if (ti.get_dimension() == 0) {
94  // set the type info based on the literal string
95  ti.set_scale(after_dot.length());
96  ti.set_dimension(before_dot_digits + ti.get_scale());
97  ti.set_notnull(false);
98  } else {
99  if (before_dot_digits + ti.get_scale() > static_cast<size_t>(ti.get_dimension())) {
100  throw std::runtime_error("numeric value " + std::string(s) +
101  " exceeds the maximum precision of " +
103  }
104  for (ssize_t i = 0; i < static_cast<ssize_t>(after_dot.length()) - ti.get_scale();
105  i++) {
106  fraction /= 10; // truncate the digits after decimal point.
107  }
108  }
109  // the following loop can be made more efficient if needed
110  for (int i = 0; i < ti.get_scale(); i++) {
111  result *= 10;
112  }
113  if (result < 0) {
114  result -= fraction;
115  } else {
116  result += fraction;
117  }
118  return result * sign;
119 }
120 
121 /*
122  * @brief convert string to a datum
123  */
124 Datum StringToDatum(std::string_view s, SQLTypeInfo& ti) {
125  Datum d;
126  try {
127  switch (ti.get_type()) {
128  case kARRAY:
129  case kCOLUMN:
130  break;
131  case kBOOLEAN:
132  if (s == "t" || s == "T" || s == "1" || to_upper(std::string(s)) == "TRUE") {
133  d.boolval = true;
134  } else if (s == "f" || s == "F" || s == "0" ||
135  to_upper(std::string(s)) == "FALSE") {
136  d.boolval = false;
137  } else {
138  throw std::runtime_error("Invalid string for boolean " + std::string(s));
139  }
140  break;
141  case kNUMERIC:
142  case kDECIMAL:
143  d.bigintval = parse_numeric(s, ti);
144  break;
145  case kBIGINT:
146  d.bigintval = std::stoll(std::string(s));
147  break;
148  case kINT:
149  d.intval = std::stoi(std::string(s));
150  break;
151  case kSMALLINT:
152  d.smallintval = std::stoi(std::string(s));
153  break;
154  case kTINYINT:
155  d.tinyintval = std::stoi(std::string(s));
156  break;
157  case kFLOAT:
158  d.floatval = std::stof(std::string(s));
159  break;
160  case kDOUBLE:
161  d.doubleval = std::stod(std::string(s));
162  break;
163  case kTIME:
164  d.bigintval = DateTimeStringValidate<kTIME>()(std::string(s), ti.get_dimension());
165  break;
166  case kTIMESTAMP:
167  d.bigintval =
168  DateTimeStringValidate<kTIMESTAMP>()(std::string(s), ti.get_dimension());
169  break;
170  case kDATE:
171  d.bigintval = DateTimeStringValidate<kDATE>()(std::string(s), ti.get_dimension());
172  break;
173  case kPOINT:
174  case kLINESTRING:
175  case kPOLYGON:
176  case kMULTIPOLYGON:
177  throw std::runtime_error("Internal error: geometry type in StringToDatum.");
178  default:
179  throw std::runtime_error("Internal error: invalid type in StringToDatum.");
180  }
181  } catch (const std::invalid_argument&) {
182  throw std::runtime_error("Invalid conversion from string to " + ti.get_type_name());
183  } catch (const std::out_of_range&) {
184  throw std::runtime_error("Got out of range error during conversion from string to " +
185  ti.get_type_name());
186  }
187  return d;
188 }
189 
190 bool DatumEqual(const Datum a, const Datum b, const SQLTypeInfo& ti) {
191  switch (ti.get_type()) {
192  case kBOOLEAN:
193  return a.boolval == b.boolval;
194  case kBIGINT:
195  case kNUMERIC:
196  case kDECIMAL:
197  return a.bigintval == b.bigintval;
198  case kINT:
199  return a.intval == b.intval;
200  case kSMALLINT:
201  return a.smallintval == b.smallintval;
202  case kTINYINT:
203  return a.tinyintval == b.tinyintval;
204  case kFLOAT:
205  return a.floatval == b.floatval;
206  case kDOUBLE:
207  return a.doubleval == b.doubleval;
208  case kTIME:
209  case kTIMESTAMP:
210  case kDATE:
211  case kINTERVAL_DAY_TIME:
213  return a.bigintval == b.bigintval;
214  case kTEXT:
215  case kVARCHAR:
216  case kCHAR:
217  if (ti.get_compression() == kENCODING_DICT) {
218  return a.intval == b.intval;
219  }
220  return *a.stringval == *b.stringval;
221  default:
222  return false;
223  }
224  return false;
225 }
226 
227 /*
228  * @brief convert datum to string
229  */
230 std::string DatumToString(Datum d, const SQLTypeInfo& ti) {
231  constexpr size_t buf_size = 32;
232  char buf[buf_size]; // Hold "2000-03-01 12:34:56.123456789" and large years.
233  static_assert(sizeof(int64_t) <= sizeof(time_t));
234  switch (ti.get_type()) {
235  case kBOOLEAN:
236  if (d.boolval) {
237  return "t";
238  }
239  return "f";
240  case kNUMERIC:
241  case kDECIMAL: {
242  // we need to consider buf_size including the scale and null terminator
243  char str[ti.get_dimension() + ti.get_scale() + 2];
244  double v = (double)d.bigintval / pow(10, ti.get_scale());
245  sprintf(str, "%*.*f", ti.get_dimension(), ti.get_scale(), v);
246  return std::string(str);
247  }
248  case kINT:
249  return std::to_string(d.intval);
250  case kSMALLINT:
251  return std::to_string(d.smallintval);
252  case kTINYINT:
253  return std::to_string(d.tinyintval);
254  case kBIGINT:
255  return std::to_string(d.bigintval);
256  case kFLOAT:
257  return std::to_string(d.floatval);
258  case kDOUBLE:
259  return std::to_string(d.doubleval);
260  case kTIME: {
261  std::tm tm_struct;
262  gmtime_r(reinterpret_cast<time_t*>(&d.bigintval), &tm_struct);
263  strftime(buf, buf_size, "%T", &tm_struct);
264  return std::string(buf);
265  }
266  case kTIMESTAMP: {
267  std::tm tm_struct;
268  if (ti.is_high_precision_timestamp()) {
270  time_t const sec = static_cast<time_t>(floor_div(d.bigintval, scale));
271  int const frac = unsigned_mod(d.bigintval, scale);
272  gmtime_r(&sec, &tm_struct);
273  size_t const datetime_len = shared::formatDateTime(buf, buf_size, &tm_struct);
274  CHECK_LE(19u, datetime_len); // 19 == strlen("YYYY-MM-DD HH:MM:SS")
275  constexpr size_t max_frac_len = 10; // == strlen(".123456789")
276  CHECK_LT(datetime_len + max_frac_len, buf_size);
277  int const frac_len = snprintf(
278  buf + datetime_len, max_frac_len + 1, ".%0*d", ti.get_dimension(), frac);
279  CHECK_EQ(frac_len, 1 + ti.get_dimension());
280  } else {
281  time_t const sec = static_cast<time_t>(d.bigintval);
282  gmtime_r(&sec, &tm_struct);
283  size_t const datetime_len = shared::formatDateTime(buf, buf_size, &tm_struct);
284  CHECK_LT(0u, datetime_len);
285  }
286  return buf;
287  }
288  case kDATE: {
289  std::tm tm_struct;
290  time_t ntimeval = static_cast<time_t>(d.bigintval);
291  gmtime_r(&ntimeval, &tm_struct);
292  size_t const date_len = shared::formatDate(buf, buf_size, &tm_struct);
293  CHECK_LE(10u, date_len); // 10 == strlen("YYYY-MM-DD")
294  return std::string(buf);
295  }
296  case kINTERVAL_DAY_TIME:
297  return std::to_string(d.bigintval) + " ms (day-time interval)";
299  return std::to_string(d.bigintval) + " month(s) (year-month interval)";
300  case kTEXT:
301  case kVARCHAR:
302  case kCHAR:
303  return *d.stringval;
304  default:
305  throw std::runtime_error("Internal error: invalid type " + ti.get_type_name() +
306  " in DatumToString.");
307  }
308  return "";
309 }
310 
312  switch (ti.get_size()) {
313  case 1:
314  return kTINYINT;
315  case 2:
316  return kSMALLINT;
317  case 4:
318  return kINT;
319  case 8:
320  return kBIGINT;
321  default:
322  CHECK(false);
323  }
324  return kNULLT;
325 }
326 
327 int64_t convert_decimal_value_to_scale(const int64_t decimal_value,
328  const SQLTypeInfo& type_info,
329  const SQLTypeInfo& new_type_info) {
330  auto converted_decimal_value = decimal_value;
331  if (new_type_info.get_scale() > type_info.get_scale()) {
332  for (int i = 0; i < new_type_info.get_scale() - type_info.get_scale(); i++) {
333  converted_decimal_value *= 10;
334  }
335  } else if (new_type_info.get_scale() < type_info.get_scale()) {
336  for (int i = 0; i < type_info.get_scale() - new_type_info.get_scale(); i++) {
337  if (converted_decimal_value > 0) {
338  converted_decimal_value = (converted_decimal_value + 5) / 10;
339  } else {
340  converted_decimal_value = (converted_decimal_value - 5) / 10;
341  }
342  }
343  }
344  return converted_decimal_value;
345 }
int8_t tinyintval
Definition: sqltypes.h:134
#define CHECK_EQ(x, y)
Definition: Logger.h:205
HOST DEVICE int get_size() const
Definition: sqltypes.h:268
std::string DatumToString(Datum d, const SQLTypeInfo &ti)
Definition: Datum.cpp:230
Definition: sqltypes.h:50
SQLTypes
Definition: sqltypes.h:39
int64_t parse_numeric(const std::string_view s, SQLTypeInfo &ti)
Definition: Datum.cpp:71
size_t formatDateTime(char *buf, size_t const max, std::tm const *tm)
Definition: misc.cpp:37
bool boolval
Definition: sqltypes.h:133
HOST DEVICE int get_scale() const
Definition: sqltypes.h:263
Constants for Builtin SQL Types supported by OmniSci.
DEVICE int64_t floor_div(int64_t const dividend, int64_t const divisor)
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:258
int32_t intval
Definition: sqltypes.h:136
std::string to_string(char const *&&v)
float floatval
Definition: sqltypes.h:138
CHECK(cgen_state)
bool DatumEqual(const Datum a, const Datum b, const SQLTypeInfo &ti)
Definition: Datum.cpp:190
static std::string type_name[kSQLTYPE_LAST]
Definition: sqltypes.h:664
void set_scale(int s)
Definition: sqltypes.h:353
int64_t bigintval
Definition: sqltypes.h:137
int16_t smallintval
Definition: sqltypes.h:135
Datum StringToDatum(std::string_view s, SQLTypeInfo &ti)
Definition: Datum.cpp:124
std::string * stringval
Definition: sqltypes.h:142
std::string to_upper(const std::string &str)
SQLTypes decimal_to_int_type(const SQLTypeInfo &ti)
Definition: Datum.cpp:311
#define CHECK_LT(x, y)
Definition: Logger.h:207
Definition: sqltypes.h:53
Definition: sqltypes.h:54
static std::string comp_name[kENCODING_LAST]
Definition: sqltypes.h:665
int64_t const int32_t sz assert(dest)
#define CHECK_LE(x, y)
Definition: Logger.h:208
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:266
int64_t convert_decimal_value_to_scale(const int64_t decimal_value, const SQLTypeInfo &type_info, const SQLTypeInfo &new_type_info)
Definition: Datum.cpp:327
void set_dimension(int d)
Definition: sqltypes.h:350
DEVICE int64_t unsigned_mod(int64_t const dividend, int64_t const divisor)
HOST DEVICE int get_dimension() const
Definition: sqltypes.h:260
std::string get_type_name() const
Definition: sqltypes.h:361
Definition: sqltypes.h:42
size_t formatDate(char *buf, size_t const max, std::tm const *tm)
Definition: misc.cpp:23
void set_notnull(bool n)
Definition: sqltypes.h:355
constexpr int64_t get_timestamp_precision_scale(const int32_t dimen)
Definition: DateTimeUtils.h:51
bool is_high_precision_timestamp() const
Definition: sqltypes.h:642
Definition: sqltypes.h:46
double doubleval
Definition: sqltypes.h:139