Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SAP HANA Spatial Driver
4 : * Purpose: OGRHanaFeatureReader class implementation
5 : * Author: Maxim Rylov
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2020, SAP SE
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "ogrhanafeaturereader.h"
14 : #include "ogrhanautils.h"
15 :
16 : #include "cpl_time.h"
17 :
18 : #include <algorithm>
19 : #include <cmath>
20 : #include <cstring>
21 : #include <ctime>
22 : #include <limits>
23 : #include <sstream>
24 :
25 : #include "odbc/Types.h"
26 :
27 : namespace OGRHANA
28 : {
29 : namespace
30 : {
31 :
32 : template <typename T>
33 0 : odbc::String CreateStringFromValues(const T *elements, int numElements,
34 : std::string (*toString)(T e))
35 : {
36 0 : if (numElements == 0)
37 0 : return odbc::String();
38 :
39 0 : std::ostringstream os;
40 0 : for (int i = 0; i < numElements; ++i)
41 : {
42 0 : if (i > 0)
43 0 : os << ARRAY_VALUES_DELIMITER;
44 0 : os << toString(elements[i]);
45 : }
46 0 : return odbc::String(os.str());
47 : }
48 :
49 1 : template <typename T> T castInt(int value)
50 : {
51 2 : if (value < std::numeric_limits<T>::min() ||
52 1 : value > std::numeric_limits<T>::max())
53 0 : throw std::overflow_error("Integer value lies outside of the range");
54 1 : return static_cast<T>(value);
55 : }
56 :
57 : // Specialization to make Coverity Scan happy
58 1 : template <> int castInt(int value)
59 : {
60 1 : return value;
61 : }
62 :
63 2 : template <typename T> T strToInt(const char *value)
64 : {
65 2 : return castInt<T>(std::stoi(value));
66 : }
67 :
68 : } // anonymous namespace
69 :
70 136 : OGRHanaFeatureReader::OGRHanaFeatureReader(const OGRFeature &feature)
71 136 : : feature_(feature)
72 : {
73 136 : }
74 :
75 1 : odbc::Boolean OGRHanaFeatureReader::GetFieldAsBoolean(int fieldIndex) const
76 : {
77 1 : if (IsFieldSet(fieldIndex))
78 0 : return feature_.GetFieldAsInteger(fieldIndex) == 1;
79 :
80 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
81 1 : if (defaultValue == nullptr)
82 0 : return odbc::Boolean();
83 :
84 1 : return (EQUAL(defaultValue, "1") || EQUAL(defaultValue, "'t'"));
85 : }
86 :
87 0 : odbc::Byte OGRHanaFeatureReader::GetFieldAsByte(int fieldIndex) const
88 : {
89 0 : if (IsFieldSet(fieldIndex))
90 : return odbc::Byte(
91 0 : castInt<std::int8_t>(feature_.GetFieldAsInteger(fieldIndex)));
92 :
93 0 : const char *defaultValue = GetDefaultValue(fieldIndex);
94 0 : if (defaultValue == nullptr)
95 0 : return odbc::Byte();
96 0 : return odbc::Byte(strToInt<std::int8_t>(defaultValue));
97 : }
98 :
99 1 : odbc::Short OGRHanaFeatureReader::GetFieldAsShort(int fieldIndex) const
100 : {
101 1 : if (IsFieldSet(fieldIndex))
102 : return odbc::Short(
103 0 : castInt<std::int16_t>(feature_.GetFieldAsInteger(fieldIndex)));
104 :
105 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
106 1 : if (defaultValue == nullptr)
107 0 : return odbc::Short();
108 1 : return odbc::Short(strToInt<std::int16_t>(defaultValue));
109 : }
110 :
111 2 : odbc::Int OGRHanaFeatureReader::GetFieldAsInt(int fieldIndex) const
112 : {
113 2 : if (IsFieldSet(fieldIndex))
114 0 : return odbc::Int(feature_.GetFieldAsInteger(fieldIndex));
115 :
116 2 : const char *defaultValue = GetDefaultValue(fieldIndex);
117 2 : if (defaultValue == nullptr)
118 1 : return odbc::Int();
119 1 : return odbc::Int(strToInt<int>(defaultValue));
120 : }
121 :
122 127 : odbc::Long OGRHanaFeatureReader::GetFieldAsLong(int fieldIndex) const
123 : {
124 127 : if (IsFieldSet(fieldIndex))
125 111 : return odbc::Long(feature_.GetFieldAsInteger64(fieldIndex));
126 :
127 16 : const char *defaultValue = GetDefaultValue(fieldIndex);
128 16 : if (defaultValue == nullptr)
129 15 : return odbc::Long();
130 1 : return odbc::Long(std::stol(defaultValue));
131 : }
132 :
133 1 : odbc::Float OGRHanaFeatureReader::GetFieldAsFloat(int fieldIndex) const
134 : {
135 1 : if (IsFieldSet(fieldIndex))
136 : {
137 0 : double dValue = feature_.GetFieldAsDouble(fieldIndex);
138 0 : return odbc::Float(static_cast<float>(dValue));
139 : }
140 :
141 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
142 1 : if (defaultValue == nullptr)
143 0 : return odbc::Float();
144 1 : return odbc::Float(std::stof(defaultValue));
145 : }
146 :
147 128 : odbc::Double OGRHanaFeatureReader::GetFieldAsDouble(int fieldIndex) const
148 : {
149 128 : if (IsFieldSet(fieldIndex))
150 110 : return odbc::Double(feature_.GetFieldAsDouble(fieldIndex));
151 18 : const char *defaultValue = GetDefaultValue(fieldIndex);
152 18 : if (defaultValue == nullptr)
153 16 : return odbc::Double();
154 2 : return odbc::Double(std::stod(defaultValue));
155 : }
156 :
157 0 : odbc::String OGRHanaFeatureReader::GetFieldAsString(int fieldIndex,
158 : int maxCharLength) const
159 : {
160 0 : auto getString = [&](const char *str)
161 : {
162 0 : if (str == nullptr)
163 0 : return odbc::String();
164 :
165 0 : if (maxCharLength > 0 &&
166 0 : std::strlen(str) > static_cast<std::size_t>(maxCharLength))
167 : return odbc::String(
168 0 : std::string(str, static_cast<std::size_t>(maxCharLength)));
169 0 : return odbc::String(str);
170 0 : };
171 :
172 0 : if (IsFieldSet(fieldIndex))
173 0 : return getString(feature_.GetFieldAsString(fieldIndex));
174 :
175 0 : const char *defaultValue = GetDefaultValue(fieldIndex);
176 0 : if (defaultValue == nullptr)
177 0 : return odbc::String();
178 :
179 0 : if (defaultValue[0] == '\'' &&
180 0 : defaultValue[strlen(defaultValue) - 1] == '\'')
181 : {
182 0 : CPLString str(defaultValue + 1);
183 0 : str.pop_back();
184 0 : char *tmp = CPLUnescapeString(str, nullptr, CPLES_SQL);
185 0 : odbc::String ret = getString(tmp);
186 0 : CPLFree(tmp);
187 0 : return ret;
188 : }
189 :
190 0 : return odbc::String(defaultValue);
191 : }
192 :
193 254 : odbc::String OGRHanaFeatureReader::GetFieldAsNString(int fieldIndex,
194 : int maxCharLength) const
195 : {
196 127 : auto getString = [&](const char *str)
197 : {
198 127 : if (str == nullptr)
199 0 : return odbc::String();
200 :
201 127 : if (maxCharLength <= 0)
202 0 : return odbc::String(std::string(str));
203 :
204 127 : int nSrcLen = static_cast<int>(std::strlen(str));
205 127 : int nSrcLenUTF = CPLStrlenUTF8(str);
206 :
207 127 : if (nSrcLenUTF > maxCharLength)
208 : {
209 1 : CPLDebug("HANA",
210 : "Truncated field value '%s' at index %d to %d characters.",
211 1 : str, fieldIndex, maxCharLength);
212 :
213 1 : int iUTF8Char = 0;
214 9 : for (int iChar = 0; iChar < nSrcLen; ++iChar)
215 : {
216 9 : if ((str[iChar] & 0xc0) != 0x80)
217 : {
218 9 : if (iUTF8Char == maxCharLength)
219 : {
220 1 : nSrcLen = iChar;
221 1 : break;
222 : }
223 8 : ++iUTF8Char;
224 : }
225 : }
226 : }
227 :
228 : return odbc::String(
229 127 : std::string(str, static_cast<std::size_t>(nSrcLen)));
230 254 : };
231 :
232 254 : if (IsFieldSet(fieldIndex))
233 126 : return getString(feature_.GetFieldAsString(fieldIndex));
234 :
235 128 : const char *defaultValue = GetDefaultValue(fieldIndex);
236 128 : if (defaultValue == nullptr)
237 127 : return odbc::String();
238 :
239 1 : if (defaultValue[0] == '\'' &&
240 1 : defaultValue[strlen(defaultValue) - 1] == '\'')
241 : {
242 2 : CPLString str(defaultValue + 1);
243 1 : str.pop_back();
244 1 : char *tmp = CPLUnescapeString(str, nullptr, CPLES_SQL);
245 2 : odbc::String ret = getString(tmp);
246 1 : CPLFree(tmp);
247 1 : return ret;
248 : }
249 :
250 0 : return odbc::String(defaultValue);
251 : }
252 :
253 1 : odbc::Date OGRHanaFeatureReader::GetFieldAsDate(int fieldIndex) const
254 : {
255 1 : if (IsFieldSet(fieldIndex))
256 : {
257 0 : int year = 0;
258 0 : int month = 0;
259 0 : int day = 0;
260 0 : int hour = 0;
261 0 : int minute = 0;
262 0 : int timeZoneFlag = 0;
263 0 : float second = 0.0f;
264 0 : feature_.GetFieldAsDateTime(fieldIndex, &year, &month, &day, &hour,
265 : &minute, &second, &timeZoneFlag);
266 :
267 0 : return odbc::makeNullable<odbc::date>(year, month, day);
268 : }
269 :
270 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
271 1 : if (defaultValue == nullptr)
272 0 : return odbc::Date();
273 :
274 1 : if (EQUAL(defaultValue, "CURRENT_DATE"))
275 : {
276 0 : std::time_t t = std::time(nullptr);
277 0 : tm *now = std::localtime(&t);
278 0 : if (now == nullptr)
279 0 : return odbc::Date();
280 0 : return odbc::makeNullable<odbc::date>(now->tm_year + 1900,
281 0 : now->tm_mon + 1, now->tm_mday);
282 : }
283 :
284 : int year, month, day;
285 1 : sscanf(defaultValue, "'%04d/%02d/%02d'", &year, &month, &day);
286 :
287 1 : return odbc::makeNullable<odbc::date>(year, month, day);
288 : }
289 :
290 1 : odbc::Time OGRHanaFeatureReader::GetFieldAsTime(int fieldIndex) const
291 : {
292 1 : if (IsFieldSet(fieldIndex))
293 : {
294 0 : int year = 0;
295 0 : int month = 0;
296 0 : int day = 0;
297 0 : int hour = 0;
298 0 : int minute = 0;
299 0 : int timeZoneFlag = 0;
300 0 : float second = 0.0f;
301 0 : feature_.GetFieldAsDateTime(fieldIndex, &year, &month, &day, &hour,
302 : &minute, &second, &timeZoneFlag);
303 : return odbc::makeNullable<odbc::time>(hour, minute,
304 0 : static_cast<int>(round(second)));
305 : }
306 :
307 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
308 1 : if (defaultValue == nullptr)
309 0 : return odbc::Time();
310 :
311 1 : if (EQUAL(defaultValue, "CURRENT_TIME"))
312 : {
313 0 : std::time_t t = std::time(nullptr);
314 0 : tm *now = std::localtime(&t);
315 0 : if (now == nullptr)
316 0 : return odbc::Time();
317 0 : return odbc::makeNullable<odbc::time>(now->tm_hour, now->tm_min,
318 0 : now->tm_sec);
319 : }
320 :
321 1 : int hour = 0;
322 1 : int minute = 0;
323 1 : int second = 0;
324 1 : sscanf(defaultValue, "'%02d:%02d:%02d'", &hour, &minute, &second);
325 1 : return odbc::makeNullable<odbc::time>(hour, minute, second);
326 : }
327 :
328 4 : odbc::Timestamp OGRHanaFeatureReader::GetFieldAsTimestamp(int fieldIndex) const
329 : {
330 4 : if (IsFieldSet(fieldIndex))
331 : {
332 3 : int year = 0;
333 3 : int month = 0;
334 3 : int day = 0;
335 3 : int hour = 0;
336 3 : int minute = 0;
337 3 : float secondWithMillisecond = 0.0f;
338 3 : int timeZoneFlag = 0;
339 3 : feature_.GetFieldAsDateTime(fieldIndex, &year, &month, &day, &hour,
340 : &minute, &secondWithMillisecond,
341 : &timeZoneFlag);
342 3 : double seconds = 0.0;
343 : double milliseconds =
344 3 : std::modf(static_cast<double>(secondWithMillisecond), &seconds);
345 3 : int second = static_cast<int>(std::floor(seconds));
346 3 : int millisecond = static_cast<int>(std::floor(milliseconds * 1000));
347 :
348 3 : if (!(timeZoneFlag == 0 || timeZoneFlag == 100 || timeZoneFlag == 1))
349 : {
350 : struct tm time;
351 1 : time.tm_year = year - 1900;
352 1 : time.tm_mon = month - 1;
353 1 : time.tm_mday = day;
354 1 : time.tm_hour = hour;
355 1 : time.tm_min = minute;
356 1 : time.tm_sec = second;
357 1 : GIntBig dt = CPLYMDHMSToUnixTime(&time);
358 1 : const int tzoffset = std::abs(timeZoneFlag - 100) * 15;
359 1 : dt -= tzoffset * 60;
360 1 : CPLUnixTimeToYMDHMS(dt, &time);
361 1 : year = time.tm_year + 1900;
362 1 : month = time.tm_mon + 1;
363 1 : day = time.tm_mday;
364 1 : hour = time.tm_hour;
365 1 : minute = time.tm_min;
366 1 : second = time.tm_sec;
367 : }
368 :
369 : return odbc::makeNullable<odbc::timestamp>(year, month, day, hour,
370 3 : minute, second, millisecond);
371 : }
372 :
373 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
374 1 : if (defaultValue == nullptr)
375 0 : return odbc::Timestamp();
376 :
377 1 : if (EQUAL(defaultValue, "CURRENT_TIMESTAMP"))
378 : {
379 0 : time_t t = std::time(nullptr);
380 0 : tm *now = std::localtime(&t);
381 0 : if (now == nullptr)
382 0 : return odbc::Timestamp();
383 : return odbc::makeNullable<odbc::timestamp>(
384 0 : now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour,
385 0 : now->tm_min, now->tm_sec, 0);
386 : }
387 :
388 1 : int year = 0;
389 1 : int month = 0;
390 1 : int day = 0;
391 1 : int hour = 0;
392 1 : int minute = 0;
393 1 : int second = 0;
394 1 : int millisecond = 0;
395 :
396 1 : if (strchr(defaultValue, '.') == nullptr)
397 0 : sscanf(defaultValue, "'%04d/%02d/%02d %02d:%02d:%02d'", &year, &month,
398 : &day, &hour, &minute, &second);
399 : else
400 1 : sscanf(defaultValue, "'%04d/%02d/%02d %02d:%02d:%02d.%03d'", &year,
401 : &month, &day, &hour, &minute, &second, &millisecond);
402 :
403 : return odbc::makeNullable<odbc::timestamp>(year, month, day, hour, minute,
404 1 : second, millisecond);
405 : }
406 :
407 3 : Binary OGRHanaFeatureReader::GetFieldAsBinary(int fieldIndex) const
408 : {
409 3 : if (IsFieldSet(fieldIndex))
410 : {
411 2 : int size = 0;
412 2 : GByte *data = feature_.GetFieldAsBinary(fieldIndex, &size);
413 2 : return {data, static_cast<std::size_t>(size)};
414 : }
415 :
416 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
417 1 : if (defaultValue == nullptr)
418 0 : return {nullptr, 0U};
419 :
420 : return {const_cast<GByte *>(reinterpret_cast<const GByte *>(defaultValue)),
421 1 : std::strlen(defaultValue)};
422 : }
423 :
424 1 : odbc::String OGRHanaFeatureReader::GetFieldAsIntArray(int fieldIndex) const
425 : {
426 1 : if (!IsFieldSet(fieldIndex))
427 1 : return odbc::String();
428 :
429 : int numElements;
430 : const int *values =
431 0 : feature_.GetFieldAsIntegerList(fieldIndex, &numElements);
432 0 : return CreateStringFromValues<int>(values, numElements, &std::to_string);
433 : }
434 :
435 1 : odbc::String OGRHanaFeatureReader::GetFieldAsBigIntArray(int fieldIndex) const
436 : {
437 1 : if (!IsFieldSet(fieldIndex))
438 1 : return odbc::String();
439 :
440 : int numElements;
441 : const GIntBig *values =
442 0 : feature_.GetFieldAsInteger64List(fieldIndex, &numElements);
443 : return CreateStringFromValues<GIntBig>(values, numElements,
444 0 : &std::to_string);
445 : }
446 :
447 0 : odbc::String OGRHanaFeatureReader::GetFieldAsRealArray(int fieldIndex) const
448 : {
449 0 : if (!IsFieldSet(fieldIndex))
450 0 : return odbc::String();
451 :
452 : int numElements;
453 : const double *values =
454 0 : feature_.GetFieldAsDoubleList(fieldIndex, &numElements);
455 : return CreateStringFromValues<double>(
456 : values, numElements,
457 0 : [](double value) -> std::string
458 : {
459 0 : return std::isnan(value)
460 : ? "NULL"
461 0 : : std::to_string(static_cast<float>(value));
462 0 : });
463 : }
464 :
465 1 : odbc::String OGRHanaFeatureReader::GetFieldAsDoubleArray(int fieldIndex) const
466 : {
467 1 : if (!IsFieldSet(fieldIndex))
468 1 : return odbc::String();
469 :
470 : int numElements;
471 : const double *values =
472 0 : feature_.GetFieldAsDoubleList(fieldIndex, &numElements);
473 : return CreateStringFromValues<double>(
474 : values, numElements,
475 0 : [](double value) -> std::string
476 0 : { return std::isnan(value) ? "NULL" : std::to_string(value); });
477 : }
478 :
479 1 : odbc::String OGRHanaFeatureReader::GetFieldAsStringArray(int fieldIndex) const
480 : {
481 1 : if (!IsFieldSet(fieldIndex))
482 1 : return odbc::String();
483 :
484 0 : char **items = feature_.GetFieldAsStringList(fieldIndex);
485 0 : if (items == nullptr)
486 0 : return odbc::String();
487 :
488 0 : std::ostringstream os;
489 0 : bool firstItem = true;
490 0 : while (items && *items)
491 : {
492 0 : if (!firstItem)
493 0 : os << ARRAY_VALUES_DELIMITER;
494 :
495 0 : char *itemValue = *items;
496 0 : if (*itemValue != '\0')
497 : {
498 0 : os << '\'';
499 0 : while (*itemValue)
500 : {
501 0 : if (*itemValue == '\'')
502 0 : os << "'";
503 0 : os << *itemValue;
504 0 : ++itemValue;
505 : }
506 0 : os << '\'';
507 : }
508 :
509 0 : ++items;
510 0 : firstItem = false;
511 : }
512 :
513 0 : return odbc::String(os.str());
514 : }
515 :
516 171 : const char *OGRHanaFeatureReader::GetDefaultValue(int fieldIndex) const
517 : {
518 171 : const OGRFieldDefn *fieldDef = feature_.GetFieldDefnRef(fieldIndex);
519 171 : return fieldDef->GetDefault();
520 : }
521 :
522 527 : bool OGRHanaFeatureReader::IsFieldSet(int fieldIndex) const
523 : {
524 527 : return feature_.IsFieldSet(fieldIndex) && !feature_.IsFieldNull(fieldIndex);
525 : }
526 :
527 : } // namespace OGRHANA
|