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