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: 2024-11-21 22:18:42 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 :         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

Generated by: LCOV version 1.14