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 : size_t nSrcLen = std::strlen(str);
205 127 : const size_t nSrcLenUTF = CPLStrlenUTF8Ex(str);
206 :
207 127 : if (nSrcLenUTF > static_cast<size_t>(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 : size_t iUTF8Char = 0;
214 9 : for (size_t iChar = 0; iChar < nSrcLen; ++iChar)
215 : {
216 9 : if ((str[iChar] & 0xc0) != 0x80)
217 : {
218 9 : if (iUTF8Char == static_cast<size_t>(maxCharLength))
219 : {
220 1 : nSrcLen = iChar;
221 1 : break;
222 : }
223 8 : ++iUTF8Char;
224 : }
225 : }
226 : }
227 :
228 127 : return odbc::String(std::string(str, nSrcLen));
229 254 : };
230 :
231 254 : if (IsFieldSet(fieldIndex))
232 126 : return getString(feature_.GetFieldAsString(fieldIndex));
233 :
234 128 : const char *defaultValue = GetDefaultValue(fieldIndex);
235 128 : if (defaultValue == nullptr)
236 127 : return odbc::String();
237 :
238 1 : if (defaultValue[0] == '\'' &&
239 1 : defaultValue[strlen(defaultValue) - 1] == '\'')
240 : {
241 2 : CPLString str(defaultValue + 1);
242 1 : str.pop_back();
243 1 : char *tmp = CPLUnescapeString(str, nullptr, CPLES_SQL);
244 2 : odbc::String ret = getString(tmp);
245 1 : CPLFree(tmp);
246 1 : return ret;
247 : }
248 :
249 0 : return odbc::String(defaultValue);
250 : }
251 :
252 1 : odbc::Date OGRHanaFeatureReader::GetFieldAsDate(int fieldIndex) const
253 : {
254 1 : if (IsFieldSet(fieldIndex))
255 : {
256 0 : int year = 0;
257 0 : int month = 0;
258 0 : int day = 0;
259 0 : int hour = 0;
260 0 : int minute = 0;
261 0 : int timeZoneFlag = 0;
262 0 : float second = 0.0f;
263 0 : feature_.GetFieldAsDateTime(fieldIndex, &year, &month, &day, &hour,
264 : &minute, &second, &timeZoneFlag);
265 :
266 0 : return odbc::makeNullable<odbc::date>(year, month, day);
267 : }
268 :
269 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
270 1 : if (defaultValue == nullptr)
271 0 : return odbc::Date();
272 :
273 1 : if (EQUAL(defaultValue, "CURRENT_DATE"))
274 : {
275 0 : std::time_t t = std::time(nullptr);
276 0 : tm *now = std::localtime(&t);
277 0 : if (now == nullptr)
278 0 : return odbc::Date();
279 0 : return odbc::makeNullable<odbc::date>(now->tm_year + 1900,
280 0 : now->tm_mon + 1, now->tm_mday);
281 : }
282 :
283 : int year, month, day;
284 1 : sscanf(defaultValue, "'%04d/%02d/%02d'", &year, &month, &day);
285 :
286 1 : return odbc::makeNullable<odbc::date>(year, month, day);
287 : }
288 :
289 1 : odbc::Time OGRHanaFeatureReader::GetFieldAsTime(int fieldIndex) const
290 : {
291 1 : if (IsFieldSet(fieldIndex))
292 : {
293 0 : int year = 0;
294 0 : int month = 0;
295 0 : int day = 0;
296 0 : int hour = 0;
297 0 : int minute = 0;
298 0 : int timeZoneFlag = 0;
299 0 : float second = 0.0f;
300 0 : feature_.GetFieldAsDateTime(fieldIndex, &year, &month, &day, &hour,
301 : &minute, &second, &timeZoneFlag);
302 : return odbc::makeNullable<odbc::time>(hour, minute,
303 0 : static_cast<int>(round(second)));
304 : }
305 :
306 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
307 1 : if (defaultValue == nullptr)
308 0 : return odbc::Time();
309 :
310 1 : if (EQUAL(defaultValue, "CURRENT_TIME"))
311 : {
312 0 : std::time_t t = std::time(nullptr);
313 0 : tm *now = std::localtime(&t);
314 0 : if (now == nullptr)
315 0 : return odbc::Time();
316 0 : return odbc::makeNullable<odbc::time>(now->tm_hour, now->tm_min,
317 0 : now->tm_sec);
318 : }
319 :
320 1 : int hour = 0;
321 1 : int minute = 0;
322 1 : int second = 0;
323 1 : sscanf(defaultValue, "'%02d:%02d:%02d'", &hour, &minute, &second);
324 1 : return odbc::makeNullable<odbc::time>(hour, minute, second);
325 : }
326 :
327 4 : odbc::Timestamp OGRHanaFeatureReader::GetFieldAsTimestamp(int fieldIndex) const
328 : {
329 4 : if (IsFieldSet(fieldIndex))
330 : {
331 3 : int year = 0;
332 3 : int month = 0;
333 3 : int day = 0;
334 3 : int hour = 0;
335 3 : int minute = 0;
336 3 : float secondWithMillisecond = 0.0f;
337 3 : int timeZoneFlag = 0;
338 3 : feature_.GetFieldAsDateTime(fieldIndex, &year, &month, &day, &hour,
339 : &minute, &secondWithMillisecond,
340 : &timeZoneFlag);
341 3 : double seconds = 0.0;
342 : double milliseconds =
343 3 : std::modf(static_cast<double>(secondWithMillisecond), &seconds);
344 3 : int second = static_cast<int>(std::floor(seconds));
345 3 : int millisecond = static_cast<int>(std::floor(milliseconds * 1000));
346 :
347 3 : if (!(timeZoneFlag == 0 || timeZoneFlag == 100 || timeZoneFlag == 1))
348 : {
349 : struct tm time;
350 1 : time.tm_year = year - 1900;
351 1 : time.tm_mon = month - 1;
352 1 : time.tm_mday = day;
353 1 : time.tm_hour = hour;
354 1 : time.tm_min = minute;
355 1 : time.tm_sec = second;
356 1 : GIntBig dt = CPLYMDHMSToUnixTime(&time);
357 1 : const int tzoffset = std::abs(timeZoneFlag - 100) * 15;
358 1 : dt -= tzoffset * 60;
359 1 : CPLUnixTimeToYMDHMS(dt, &time);
360 1 : year = time.tm_year + 1900;
361 1 : month = time.tm_mon + 1;
362 1 : day = time.tm_mday;
363 1 : hour = time.tm_hour;
364 1 : minute = time.tm_min;
365 1 : second = time.tm_sec;
366 : }
367 :
368 : return odbc::makeNullable<odbc::timestamp>(year, month, day, hour,
369 3 : minute, second, millisecond);
370 : }
371 :
372 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
373 1 : if (defaultValue == nullptr)
374 0 : return odbc::Timestamp();
375 :
376 1 : if (EQUAL(defaultValue, "CURRENT_TIMESTAMP"))
377 : {
378 0 : time_t t = std::time(nullptr);
379 0 : tm *now = std::localtime(&t);
380 0 : if (now == nullptr)
381 0 : return odbc::Timestamp();
382 : return odbc::makeNullable<odbc::timestamp>(
383 0 : now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour,
384 0 : now->tm_min, now->tm_sec, 0);
385 : }
386 :
387 1 : int year = 0;
388 1 : int month = 0;
389 1 : int day = 0;
390 1 : int hour = 0;
391 1 : int minute = 0;
392 1 : int second = 0;
393 1 : int millisecond = 0;
394 :
395 1 : if (strchr(defaultValue, '.') == nullptr)
396 0 : sscanf(defaultValue, "'%04d/%02d/%02d %02d:%02d:%02d'", &year, &month,
397 : &day, &hour, &minute, &second);
398 : else
399 1 : sscanf(defaultValue, "'%04d/%02d/%02d %02d:%02d:%02d.%03d'", &year,
400 : &month, &day, &hour, &minute, &second, &millisecond);
401 :
402 : return odbc::makeNullable<odbc::timestamp>(year, month, day, hour, minute,
403 1 : second, millisecond);
404 : }
405 :
406 3 : Binary OGRHanaFeatureReader::GetFieldAsBinary(int fieldIndex) const
407 : {
408 3 : if (IsFieldSet(fieldIndex))
409 : {
410 2 : int size = 0;
411 2 : GByte *data = feature_.GetFieldAsBinary(fieldIndex, &size);
412 2 : return {data, static_cast<std::size_t>(size)};
413 : }
414 :
415 1 : const char *defaultValue = GetDefaultValue(fieldIndex);
416 1 : if (defaultValue == nullptr)
417 0 : return {nullptr, 0U};
418 :
419 : return {const_cast<GByte *>(reinterpret_cast<const GByte *>(defaultValue)),
420 1 : std::strlen(defaultValue)};
421 : }
422 :
423 1 : odbc::String OGRHanaFeatureReader::GetFieldAsIntArray(int fieldIndex) const
424 : {
425 1 : if (!IsFieldSet(fieldIndex))
426 1 : return odbc::String();
427 :
428 : int numElements;
429 : const int *values =
430 0 : feature_.GetFieldAsIntegerList(fieldIndex, &numElements);
431 0 : return CreateStringFromValues<int>(values, numElements, &std::to_string);
432 : }
433 :
434 1 : odbc::String OGRHanaFeatureReader::GetFieldAsBigIntArray(int fieldIndex) const
435 : {
436 1 : if (!IsFieldSet(fieldIndex))
437 1 : return odbc::String();
438 :
439 : int numElements;
440 : const GIntBig *values =
441 0 : feature_.GetFieldAsInteger64List(fieldIndex, &numElements);
442 : return CreateStringFromValues<GIntBig>(values, numElements,
443 0 : &std::to_string);
444 : }
445 :
446 0 : odbc::String OGRHanaFeatureReader::GetFieldAsRealArray(int fieldIndex) const
447 : {
448 0 : if (!IsFieldSet(fieldIndex))
449 0 : return odbc::String();
450 :
451 : int numElements;
452 : const double *values =
453 0 : feature_.GetFieldAsDoubleList(fieldIndex, &numElements);
454 : return CreateStringFromValues<double>(
455 : values, numElements,
456 0 : [](double value) -> std::string
457 : {
458 0 : return std::isnan(value)
459 : ? "NULL"
460 0 : : std::to_string(static_cast<float>(value));
461 0 : });
462 : }
463 :
464 1 : odbc::String OGRHanaFeatureReader::GetFieldAsDoubleArray(int fieldIndex) const
465 : {
466 1 : if (!IsFieldSet(fieldIndex))
467 1 : return odbc::String();
468 :
469 : int numElements;
470 : const double *values =
471 0 : feature_.GetFieldAsDoubleList(fieldIndex, &numElements);
472 : return CreateStringFromValues<double>(
473 : values, numElements,
474 0 : [](double value) -> std::string
475 0 : { return std::isnan(value) ? "NULL" : std::to_string(value); });
476 : }
477 :
478 1 : odbc::String OGRHanaFeatureReader::GetFieldAsStringArray(int fieldIndex) const
479 : {
480 1 : if (!IsFieldSet(fieldIndex))
481 1 : return odbc::String();
482 :
483 0 : char **items = feature_.GetFieldAsStringList(fieldIndex);
484 0 : if (items == nullptr)
485 0 : return odbc::String();
486 :
487 0 : std::ostringstream os;
488 0 : bool firstItem = true;
489 0 : while (items && *items)
490 : {
491 0 : if (!firstItem)
492 0 : os << ARRAY_VALUES_DELIMITER;
493 :
494 0 : char *itemValue = *items;
495 0 : if (*itemValue != '\0')
496 : {
497 0 : os << '\'';
498 0 : while (*itemValue)
499 : {
500 0 : if (*itemValue == '\'')
501 0 : os << "'";
502 0 : os << *itemValue;
503 0 : ++itemValue;
504 : }
505 0 : os << '\'';
506 : }
507 :
508 0 : ++items;
509 0 : firstItem = false;
510 : }
511 :
512 0 : return odbc::String(os.str());
513 : }
514 :
515 171 : const char *OGRHanaFeatureReader::GetDefaultValue(int fieldIndex) const
516 : {
517 171 : const OGRFieldDefn *fieldDef = feature_.GetFieldDefnRef(fieldIndex);
518 171 : return fieldDef->GetDefault();
519 : }
520 :
521 527 : bool OGRHanaFeatureReader::IsFieldSet(int fieldIndex) const
522 : {
523 527 : return feature_.IsFieldSet(fieldIndex) && !feature_.IsFieldNull(fieldIndex);
524 : }
525 :
526 : } // namespace OGRHANA
|