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