LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/hana - ogrhanafeaturereader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 164 291 56.4 %
Date: 2025-07-13 21:00:45 Functions: 23 34 67.6 %

          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

Generated by: LCOV version 1.14