LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/hana - ogrhanalayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 426 503 84.7 %
Date: 2024-05-13 13:33:37 Functions: 27 29 93.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SAP HANA Spatial Driver
       4             :  * Purpose:  OGRHanaLayer 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 "ogr_hana.h"
      30             : #include "ogrhanafeaturewriter.h"
      31             : #include "ogrhanautils.h"
      32             : 
      33             : #include <algorithm>
      34             : #include <limits>
      35             : #include <sstream>
      36             : #include <memory>
      37             : 
      38             : #include "odbc/Exception.h"
      39             : #include "odbc/ResultSet.h"
      40             : #include "odbc/Statement.h"
      41             : #include "odbc/Types.h"
      42             : 
      43             : namespace OGRHANA
      44             : {
      45             : namespace
      46             : {
      47             : /************************************************************************/
      48             : /*                          Helper methods                              */
      49             : /************************************************************************/
      50             : 
      51          11 : CPLString BuildQuery(const char *source, const char *columns, const char *where,
      52             :                      const char *orderBy, int limit)
      53             : {
      54          11 :     std::ostringstream os;
      55          11 :     os << "SELECT " << columns << " FROM (" << source << ")";
      56          11 :     if (where != nullptr && strlen(where) > 0)
      57           0 :         os << " WHERE " << where;
      58          11 :     if (orderBy != nullptr && strlen(orderBy) > 0)
      59           0 :         os << " ORDER BY " << orderBy;
      60          11 :     if (limit >= 0)
      61           0 :         os << " LIMIT " << std::to_string(limit);
      62          33 :     return os.str();
      63             : }
      64             : 
      65          11 : CPLString BuildQuery(const char *source, const char *columns)
      66             : {
      67          11 :     return BuildQuery(source, columns, nullptr, nullptr, -1);
      68             : }
      69             : 
      70          24 : CPLString BuildSpatialFilter(int dbVersion, const OGRGeometry &geom,
      71             :                              const CPLString &clmName, int srid)
      72             : {
      73          24 :     OGREnvelope env;
      74          24 :     geom.getEnvelope(&env);
      75             : 
      76          24 :     if ((CPLIsInf(env.MinX) || CPLIsInf(env.MinY) || CPLIsInf(env.MaxX) ||
      77          22 :          CPLIsInf(env.MaxY)))
      78           2 :         return "";
      79             : 
      80          88 :     auto clampValue = [](double v)
      81             :     {
      82          88 :         constexpr double MAX_VALUE = 1e+150;
      83          88 :         if (v < -MAX_VALUE)
      84           4 :             return -MAX_VALUE;
      85          84 :         else if (v > MAX_VALUE)
      86           4 :             return MAX_VALUE;
      87          80 :         return v;
      88             :     };
      89             : 
      90          22 :     double minX = clampValue(env.MinX);
      91          22 :     double minY = clampValue(env.MinY);
      92          22 :     double maxX = clampValue(env.MaxX);
      93          22 :     double maxY = clampValue(env.MaxY);
      94             : 
      95             :     // TODO: add support for non-rectangular filter, see m_bFilterIsEnvelope
      96             :     // flag.
      97          22 :     if (dbVersion == 1)
      98           0 :         return CPLString().Printf(
      99             :             "\"%s\".ST_IntersectsRect(ST_GeomFromText('POINT(%.18g %.18g)', "
     100             :             "%d), ST_GeomFromText('POINT(%.18g %.18g)', %d)) = 1",
     101           0 :             clmName.c_str(), minX, minY, srid, maxX, maxY, srid);
     102             :     else
     103          44 :         return CPLString().Printf(
     104             :             "\"%s\".ST_IntersectsRectPlanar(ST_GeomFromText('POINT(%.18g "
     105             :             "%.18g)', %d), ST_GeomFromText('POINT(%.18g %.18g)', %d)) = 1",
     106          22 :             clmName.c_str(), minX, minY, srid, maxX, maxY, srid);
     107             : }
     108             : 
     109             : std::unique_ptr<OGRFieldDefn>
     110         156 : CreateFieldDefn(const AttributeColumnDescription &columnDesc)
     111             : {
     112         156 :     bool setFieldSize = false;
     113         156 :     bool setFieldPrecision = false;
     114             : 
     115         156 :     OGRFieldType ogrFieldType = OFTString;
     116         156 :     OGRFieldSubType ogrFieldSubType = OGRFieldSubType::OFSTNone;
     117             : 
     118         156 :     switch (columnDesc.type)
     119             :     {
     120           2 :         case odbc::SQLDataTypes::Bit:
     121             :         case odbc::SQLDataTypes::Boolean:
     122           2 :             ogrFieldType = columnDesc.isArray ? OFTIntegerList : OFTInteger;
     123           2 :             ogrFieldSubType = OGRFieldSubType::OFSTBoolean;
     124           2 :             break;
     125           3 :         case odbc::SQLDataTypes::TinyInt:
     126             :         case odbc::SQLDataTypes::SmallInt:
     127           3 :             ogrFieldType = columnDesc.isArray ? OFTIntegerList : OFTInteger;
     128           3 :             ogrFieldSubType = OGRFieldSubType::OFSTInt16;
     129           3 :             break;
     130          51 :         case odbc::SQLDataTypes::Integer:
     131          51 :             ogrFieldType = columnDesc.isArray ? OFTIntegerList : OFTInteger;
     132          51 :             break;
     133          26 :         case odbc::SQLDataTypes::BigInt:
     134          26 :             ogrFieldType = columnDesc.isArray ? OFTInteger64List : OFTInteger64;
     135          26 :             break;
     136          23 :         case odbc::SQLDataTypes::Double:
     137             :         case odbc::SQLDataTypes::Real:
     138             :         case odbc::SQLDataTypes::Float:
     139          23 :             ogrFieldType = columnDesc.isArray ? OFTRealList : OFTReal;
     140          23 :             if (columnDesc.type != odbc::SQLDataTypes::Double)
     141           1 :                 ogrFieldSubType = OGRFieldSubType::OFSTFloat32;
     142          23 :             break;
     143           3 :         case odbc::SQLDataTypes::Decimal:
     144             :         case odbc::SQLDataTypes::Numeric:
     145           3 :             ogrFieldType = columnDesc.isArray ? OFTRealList : OFTReal;
     146           3 :             setFieldPrecision = true;
     147           3 :             break;
     148          43 :         case odbc::SQLDataTypes::Char:
     149             :         case odbc::SQLDataTypes::VarChar:
     150             :         case odbc::SQLDataTypes::LongVarChar:
     151             :         case odbc::SQLDataTypes::WChar:
     152             :         case odbc::SQLDataTypes::WVarChar:
     153             :         case odbc::SQLDataTypes::WLongVarChar:
     154             :             // Note: OFTWideString is deprecated
     155          43 :             ogrFieldType = columnDesc.isArray ? OFTStringList : OFTString;
     156          43 :             setFieldSize = true;
     157          43 :             break;
     158           1 :         case odbc::SQLDataTypes::Date:
     159             :         case odbc::SQLDataTypes::TypeDate:
     160           1 :             ogrFieldType = OFTDate;
     161           1 :             break;
     162           1 :         case odbc::SQLDataTypes::Time:
     163             :         case odbc::SQLDataTypes::TypeTime:
     164           1 :             ogrFieldType = OFTTime;
     165           1 :             break;
     166           2 :         case odbc::SQLDataTypes::Timestamp:
     167             :         case odbc::SQLDataTypes::TypeTimestamp:
     168           2 :             ogrFieldType = OFTDateTime;
     169           2 :             break;
     170           1 :         case odbc::SQLDataTypes::Binary:
     171             :         case odbc::SQLDataTypes::VarBinary:
     172             :         case odbc::SQLDataTypes::LongVarBinary:
     173           1 :             ogrFieldType = OFTBinary;
     174           1 :             setFieldSize = true;
     175           1 :             break;
     176           0 :         default:
     177           0 :             break;
     178             :     }
     179             : 
     180         156 :     if (columnDesc.isArray && !IsArrayField(ogrFieldType))
     181           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     182             :                  "Array of type %s in column %s is not supported",
     183             :                  columnDesc.typeName.c_str(), columnDesc.name.c_str());
     184             : 
     185             :     auto field =
     186         156 :         std::make_unique<OGRFieldDefn>(columnDesc.name.c_str(), ogrFieldType);
     187         156 :     field->SetSubType(ogrFieldSubType);
     188         156 :     field->SetNullable(columnDesc.isNullable);
     189         156 :     if (!columnDesc.isArray)
     190             :     {
     191         145 :         if (setFieldSize)
     192          41 :             field->SetWidth(columnDesc.length);
     193         145 :         if (setFieldPrecision)
     194             :         {
     195           3 :             field->SetWidth(columnDesc.precision);
     196           3 :             field->SetPrecision(columnDesc.scale);
     197             :         }
     198             :     }
     199         156 :     if (columnDesc.defaultValue.empty())
     200         144 :         field->SetDefault(nullptr);
     201             :     else
     202          12 :         field->SetDefault(columnDesc.defaultValue.c_str());
     203         312 :     return field;
     204             : }
     205             : 
     206         513 : OGRGeometry *CreateGeometryFromWkb(const void *data, std::size_t size)
     207             : {
     208         513 :     if (size > static_cast<std::size_t>(std::numeric_limits<int>::max()))
     209           0 :         CPLError(CE_Failure, CPLE_AppDefined, "createFromWkb(): %s",
     210             :                  "Geometry size is larger than maximum integer value");
     211             : 
     212         513 :     int len = static_cast<int>(size);
     213             : 
     214         513 :     OGRGeometry *geom = nullptr;
     215         513 :     OGRErr err = OGRGeometryFactory::createFromWkb(data, nullptr, &geom, len);
     216             : 
     217         513 :     if (OGRERR_NONE == err)
     218         513 :         return geom;
     219             : 
     220           0 :     auto cplError = [](const char *message)
     221           0 :     { CPLError(CE_Failure, CPLE_AppDefined, "ReadFeature(): %s", message); };
     222             : 
     223           0 :     switch (err)
     224             :     {
     225           0 :         case OGRERR_NOT_ENOUGH_DATA:
     226           0 :             cplError("Not enough data to deserialize");
     227           0 :             return nullptr;
     228           0 :         case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
     229           0 :             cplError("Unsupported geometry type");
     230           0 :             return nullptr;
     231           0 :         case OGRERR_CORRUPT_DATA:
     232           0 :             cplError("Corrupt data");
     233           0 :             return nullptr;
     234           0 :         default:
     235           0 :             cplError("Unrecognized error");
     236           0 :             return nullptr;
     237             :     }
     238             : }
     239             : 
     240             : }  // anonymous namespace
     241             : 
     242             : /************************************************************************/
     243             : /*                           OGRHanaLayer()                             */
     244             : /************************************************************************/
     245             : 
     246         421 : OGRHanaLayer::OGRHanaLayer(OGRHanaDataSource *datasource)
     247             :     : dataSource_(datasource), rawQuery_(""), queryStatement_(""),
     248         421 :       whereClause_("")
     249             : {
     250         421 : }
     251             : 
     252             : /************************************************************************/
     253             : /*                          ~OGRHanaLayer()                             */
     254             : /************************************************************************/
     255             : 
     256         418 : OGRHanaLayer::~OGRHanaLayer()
     257             : {
     258         418 :     if (featureDefn_)
     259          48 :         featureDefn_->Release();
     260         418 : }
     261             : 
     262        1556 : void OGRHanaLayer::EnsureInitialized()
     263             : {
     264        1556 :     if (initialized_)
     265        1505 :         return;
     266             : 
     267          51 :     OGRErr err = Initialize();
     268          51 :     if (OGRERR_NONE != err)
     269             :     {
     270           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to initialize layer: %s",
     271           0 :                  GetName());
     272             :     }
     273          51 :     initialized_ = (OGRERR_NONE == err);
     274             : }
     275             : 
     276             : /************************************************************************/
     277             : /*                         ClearQueryStatement()                        */
     278             : /************************************************************************/
     279             : 
     280         186 : void OGRHanaLayer::ClearQueryStatement()
     281             : {
     282         186 :     queryStatement_.clear();
     283         186 : }
     284             : 
     285             : /************************************************************************/
     286             : /*                          GetQueryStatement()                         */
     287             : /************************************************************************/
     288             : 
     289         168 : const CPLString &OGRHanaLayer::GetQueryStatement()
     290             : {
     291         168 :     if (!queryStatement_.empty())
     292          57 :         return queryStatement_;
     293             : 
     294         111 :     EnsureInitialized();
     295             : 
     296         111 :     if (!geomColumns_.empty())
     297             :     {
     298          99 :         std::vector<CPLString> columns;
     299         198 :         for (const GeometryColumnDescription &geometryColumnDesc : geomColumns_)
     300         297 :             columns.push_back(QuotedIdentifier(geometryColumnDesc.name) +
     301         198 :                               ".ST_AsBinary() AS " +
     302         198 :                               QuotedIdentifier(geometryColumnDesc.name));
     303             : 
     304         505 :         for (const AttributeColumnDescription &attributeColumnDesc :
     305         604 :              attrColumns_)
     306         505 :             columns.push_back(QuotedIdentifier(attributeColumnDesc.name));
     307             : 
     308         198 :         queryStatement_ = CPLString().Printf(
     309         198 :             "SELECT %s FROM (%s) %s", JoinStrings(columns, ", ").c_str(),
     310         198 :             rawQuery_.c_str(), whereClause_.c_str());
     311             :     }
     312             :     else
     313             :     {
     314          12 :         if (whereClause_.empty())
     315          12 :             queryStatement_ = rawQuery_;
     316             :         else
     317             :             queryStatement_ =
     318           0 :                 CPLString().Printf("SELECT * FROM (%s) %s", rawQuery_.c_str(),
     319           0 :                                    whereClause_.c_str());
     320             :     }
     321             : 
     322         111 :     return queryStatement_;
     323             : }
     324             : 
     325             : /************************************************************************/
     326             : /*                         BuildWhereClause()                           */
     327             : /************************************************************************/
     328             : 
     329         121 : void OGRHanaLayer::BuildWhereClause()
     330             : {
     331         121 :     whereClause_ = "";
     332             : 
     333         242 :     CPLString spatialFilter;
     334         121 :     if (m_poFilterGeom != nullptr)
     335             :     {
     336          24 :         EnsureInitialized();
     337             : 
     338          24 :         OGRGeomFieldDefn *geomFieldDefn = nullptr;
     339          24 :         if (featureDefn_->GetGeomFieldCount() != 0)
     340          24 :             geomFieldDefn = featureDefn_->GetGeomFieldDefn(m_iGeomFieldFilter);
     341             : 
     342          24 :         if (geomFieldDefn != nullptr)
     343             :         {
     344             :             const GeometryColumnDescription &geomClmDesc =
     345          24 :                 geomColumns_[static_cast<std::size_t>(m_iGeomFieldFilter)];
     346          48 :             spatialFilter = BuildSpatialFilter(
     347          24 :                 dataSource_->GetMajorVersion(), *m_poFilterGeom,
     348          48 :                 geomClmDesc.name, geomClmDesc.srid);
     349             :         }
     350             :     }
     351             : 
     352         121 :     if (!attrFilter_.empty())
     353             :     {
     354          32 :         whereClause_ = " WHERE " + attrFilter_;
     355          32 :         if (!spatialFilter.empty())
     356           4 :             whereClause_ += " AND " + spatialFilter;
     357             :     }
     358          89 :     else if (!spatialFilter.empty())
     359          18 :         whereClause_ = " WHERE " + spatialFilter;
     360         121 : }
     361             : 
     362             : /************************************************************************/
     363             : /*                       EnsureBufferCapacity()                         */
     364             : /************************************************************************/
     365             : 
     366        1155 : void OGRHanaLayer::EnsureBufferCapacity(std::size_t size)
     367             : {
     368        1155 :     if (size > dataBuffer_.size())
     369          65 :         dataBuffer_.resize(size);
     370        1155 : }
     371             : 
     372             : /************************************************************************/
     373             : /*                         GetNextFeatureInternal()                     */
     374             : /************************************************************************/
     375             : 
     376         597 : OGRFeature *OGRHanaLayer::GetNextFeatureInternal()
     377             : {
     378         597 :     if (resultSet_.isNull())
     379             :     {
     380         115 :         const CPLString &queryStatement = GetQueryStatement();
     381         115 :         CPLAssert(!queryStatement.empty());
     382             : 
     383             :         try
     384             :         {
     385         115 :             odbc::StatementRef stmt = dataSource_->CreateStatement();
     386         115 :             resultSet_ = stmt->executeQuery(queryStatement.c_str());
     387             :         }
     388           0 :         catch (const odbc::Exception &ex)
     389             :         {
     390           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     391           0 :                      "Failed to execute query : %s", ex.what());
     392           0 :             return nullptr;
     393             :         }
     394             :     }
     395             : 
     396         597 :     return ReadFeature();
     397             : }
     398             : 
     399             : /************************************************************************/
     400             : /*                         GetGeometryColumnSrid()                      */
     401             : /************************************************************************/
     402             : 
     403          11 : int OGRHanaLayer::GetGeometryColumnSrid(int columnIndex) const
     404             : {
     405          22 :     if (columnIndex < 0 ||
     406          11 :         static_cast<std::size_t>(columnIndex) >= geomColumns_.size())
     407           0 :         return -1;
     408          11 :     return geomColumns_[static_cast<std::size_t>(columnIndex)].srid;
     409             : }
     410             : 
     411             : /************************************************************************/
     412             : /*                          ReadFeature()                               */
     413             : /************************************************************************/
     414             : 
     415         597 : OGRFeature *OGRHanaLayer::ReadFeature()
     416             : {
     417         597 :     if (!resultSet_->next())
     418          54 :         return nullptr;
     419             : 
     420        1086 :     auto feature = std::make_unique<OGRFeature>(featureDefn_);
     421         543 :     feature->SetFID(nextFeatureId_++);
     422             : 
     423         543 :     unsigned short paramIndex = 0;
     424             : 
     425             :     // Read geometries
     426        1061 :     for (std::size_t i = 0; i < geomColumns_.size(); ++i)
     427             :     {
     428         518 :         ++paramIndex;
     429         518 :         int geomIndex = static_cast<int>(i);
     430             : 
     431             :         OGRGeomFieldDefn *geomFieldDef =
     432         518 :             featureDefn_->GetGeomFieldDefn(geomIndex);
     433             : 
     434         518 :         if (geomFieldDef->IsIgnored())
     435           0 :             continue;
     436             : 
     437         518 :         std::size_t bufLength = resultSet_->getBinaryLength(paramIndex);
     438         518 :         if (bufLength == 0 || bufLength == odbc::ResultSet::NULL_DATA)
     439             :         {
     440           5 :             feature->SetGeomFieldDirectly(geomIndex, nullptr);
     441           5 :             continue;
     442             :         }
     443             : 
     444         513 :         OGRGeometry *geom = nullptr;
     445         513 :         if (bufLength != odbc::ResultSet::UNKNOWN_LENGTH)
     446             :         {
     447         513 :             EnsureBufferCapacity(bufLength);
     448         513 :             resultSet_->getBinaryData(paramIndex, dataBuffer_.data(),
     449             :                                       bufLength);
     450             :             geom =
     451         513 :                 CreateGeometryFromWkb(dataBuffer_.data(), dataBuffer_.size());
     452             :         }
     453             :         else
     454             :         {
     455           0 :             odbc::Binary wkb = resultSet_->getBinary(paramIndex);
     456           0 :             if (!wkb.isNull() && wkb->size() > 0)
     457           0 :                 geom = CreateGeometryFromWkb(
     458           0 :                     static_cast<const void *>(wkb->data()), wkb->size());
     459             :         }
     460             : 
     461         513 :         if (geom != nullptr)
     462         513 :             geom->assignSpatialReference(geomFieldDef->GetSpatialRef());
     463         513 :         feature->SetGeomFieldDirectly(geomIndex, geom);
     464             :     }
     465             : 
     466             :     // Read feature attributes
     467         543 :     OGRHanaFeatureWriter featWriter(*feature);
     468         543 :     int fieldIndex = -1;
     469        3182 :     for (const AttributeColumnDescription &clmDesc : attrColumns_)
     470             :     {
     471        2639 :         ++paramIndex;
     472             : 
     473        2639 :         if (clmDesc.isFeatureID)
     474             :         {
     475         528 :             if (clmDesc.type == odbc::SQLDataTypes::Integer)
     476             :             {
     477         528 :                 odbc::Int val = resultSet_->getInt(paramIndex);
     478         528 :                 if (!val.isNull())
     479         528 :                     feature->SetFID(static_cast<GIntBig>(*val));
     480             :             }
     481           0 :             else if (clmDesc.type == odbc::SQLDataTypes::BigInt)
     482             :             {
     483           0 :                 odbc::Long val = resultSet_->getLong(paramIndex);
     484           0 :                 if (!val.isNull())
     485           0 :                     feature->SetFID(static_cast<GIntBig>(*val));
     486             :             }
     487         528 :             continue;
     488             :         }
     489             : 
     490        2111 :         ++fieldIndex;
     491             : 
     492        2111 :         OGRFieldDefn *fieldDefn = featureDefn_->GetFieldDefn(fieldIndex);
     493        2111 :         if (fieldDefn->IsIgnored())
     494           0 :             continue;
     495             : 
     496        2111 :         if (clmDesc.isArray)
     497             :         {
     498          22 :             odbc::Binary val = resultSet_->getBinary(paramIndex);
     499          11 :             if (val.isNull())
     500             :             {
     501           0 :                 feature->SetFieldNull(fieldIndex);
     502           0 :                 continue;
     503             :             }
     504             : 
     505          11 :             switch (clmDesc.type)
     506             :             {
     507           1 :                 case odbc::SQLDataTypes::Boolean:
     508           1 :                     featWriter.SetFieldValueAsArray<uint8_t, int32_t>(
     509             :                         fieldIndex, val);
     510           1 :                     break;
     511           0 :                 case odbc::SQLDataTypes::TinyInt:
     512           0 :                     featWriter.SetFieldValueAsArray<uint8_t, int32_t>(
     513             :                         fieldIndex, val);
     514           0 :                     break;
     515           1 :                 case odbc::SQLDataTypes::SmallInt:
     516           1 :                     featWriter.SetFieldValueAsArray<int16_t, int32_t>(
     517             :                         fieldIndex, val);
     518           1 :                     break;
     519           2 :                 case odbc::SQLDataTypes::Integer:
     520           2 :                     featWriter.SetFieldValueAsArray<int32_t, int32_t>(
     521             :                         fieldIndex, val);
     522           2 :                     break;
     523           2 :                 case odbc::SQLDataTypes::BigInt:
     524           2 :                     featWriter.SetFieldValueAsArray<GIntBig, GIntBig>(
     525             :                         fieldIndex, val);
     526           2 :                     break;
     527           0 :                 case odbc::SQLDataTypes::Float:
     528             :                 case odbc::SQLDataTypes::Real:
     529           0 :                     featWriter.SetFieldValueAsArray<float, double>(fieldIndex,
     530             :                                                                    val);
     531           0 :                     break;
     532           2 :                 case odbc::SQLDataTypes::Double:
     533           2 :                     featWriter.SetFieldValueAsArray<double, double>(fieldIndex,
     534             :                                                                     val);
     535           2 :                     break;
     536           3 :                 case odbc::SQLDataTypes::Char:
     537             :                 case odbc::SQLDataTypes::VarChar:
     538             :                 case odbc::SQLDataTypes::LongVarChar:
     539             :                 case odbc::SQLDataTypes::WChar:
     540             :                 case odbc::SQLDataTypes::WVarChar:
     541             :                 case odbc::SQLDataTypes::WLongVarChar:
     542           3 :                     featWriter.SetFieldValueAsStringArray(fieldIndex, val);
     543           3 :                     break;
     544             :             }
     545             : 
     546          11 :             continue;
     547             :         }
     548             : 
     549        2100 :         switch (clmDesc.type)
     550             :         {
     551           1 :             case odbc::SQLDataTypes::Bit:
     552             :             case odbc::SQLDataTypes::Boolean:
     553             :             {
     554           1 :                 odbc::Boolean val = resultSet_->getBoolean(paramIndex);
     555           1 :                 featWriter.SetFieldValue(fieldIndex, val);
     556             :             }
     557           1 :             break;
     558           0 :             case odbc::SQLDataTypes::TinyInt:
     559             :             {
     560           0 :                 odbc::Byte val = resultSet_->getByte(paramIndex);
     561           0 :                 featWriter.SetFieldValue(fieldIndex, val);
     562             :             }
     563           0 :             break;
     564           1 :             case odbc::SQLDataTypes::SmallInt:
     565             :             {
     566           1 :                 odbc::Short val = resultSet_->getShort(paramIndex);
     567           1 :                 featWriter.SetFieldValue(fieldIndex, val);
     568             :             }
     569           1 :             break;
     570           2 :             case odbc::SQLDataTypes::Integer:
     571             :             {
     572           2 :                 odbc::Int val = resultSet_->getInt(paramIndex);
     573           2 :                 featWriter.SetFieldValue(fieldIndex, val);
     574             :             }
     575           2 :             break;
     576         533 :             case odbc::SQLDataTypes::BigInt:
     577             :             {
     578         533 :                 odbc::Long val = resultSet_->getLong(paramIndex);
     579         533 :                 featWriter.SetFieldValue(fieldIndex, val);
     580             :             }
     581         533 :             break;
     582           1 :             case odbc::SQLDataTypes::Real:
     583             :             case odbc::SQLDataTypes::Float:
     584             :             {
     585           1 :                 odbc::Float val = resultSet_->getFloat(paramIndex);
     586           1 :                 featWriter.SetFieldValue(fieldIndex, val);
     587             :             }
     588           1 :             break;
     589         518 :             case odbc::SQLDataTypes::Double:
     590             :             {
     591         518 :                 odbc::Double val = resultSet_->getDouble(paramIndex);
     592         518 :                 featWriter.SetFieldValue(fieldIndex, val);
     593             :             }
     594         518 :             break;
     595           1 :             case odbc::SQLDataTypes::Decimal:
     596             :             case odbc::SQLDataTypes::Numeric:
     597             :             {
     598           2 :                 odbc::Decimal val = resultSet_->getDecimal(paramIndex);
     599           1 :                 featWriter.SetFieldValue(fieldIndex, val);
     600             :             }
     601           1 :             break;
     602        1036 :             case odbc::SQLDataTypes::Char:
     603             :             case odbc::SQLDataTypes::VarChar:
     604             :             case odbc::SQLDataTypes::LongVarChar:
     605             :             // Note: NVARCHAR data type is converted to UTF-8 on the HANA side
     606             :             // when using a connection setting CHAR_AS_UTF8=1.
     607             :             case odbc::SQLDataTypes::WChar:
     608             :             case odbc::SQLDataTypes::WVarChar:
     609             :             case odbc::SQLDataTypes::WLongVarChar:
     610             :             {
     611        1036 :                 std::size_t len = resultSet_->getStringLength(paramIndex);
     612        1036 :                 if (len == odbc::ResultSet::NULL_DATA)
     613         515 :                     feature->SetFieldNull(fieldIndex);
     614         521 :                 else if (len == 0)
     615           0 :                     feature->SetField(fieldIndex, "");
     616         521 :                 else if (len != odbc::ResultSet::UNKNOWN_LENGTH)
     617             :                 {
     618         521 :                     EnsureBufferCapacity(len + 1);
     619         521 :                     resultSet_->getStringData(paramIndex, dataBuffer_.data(),
     620             :                                               len + 1);
     621         521 :                     featWriter.SetFieldValue(fieldIndex, dataBuffer_.data());
     622             :                 }
     623             :                 else
     624             :                 {
     625           0 :                     odbc::String data = resultSet_->getString(paramIndex);
     626           0 :                     featWriter.SetFieldValue(fieldIndex, data);
     627             :                 }
     628             :             }
     629        1036 :             break;
     630           1 :             case odbc::SQLDataTypes::Binary:
     631             :             case odbc::SQLDataTypes::VarBinary:
     632             :             case odbc::SQLDataTypes::LongVarBinary:
     633             :             {
     634           1 :                 std::size_t len = resultSet_->getBinaryLength(paramIndex);
     635           1 :                 if (len == 0)
     636           0 :                     feature->SetField(fieldIndex, 0,
     637             :                                       static_cast<GByte *>(nullptr));
     638           1 :                 else if (len == odbc::ResultSet::NULL_DATA)
     639           0 :                     feature->SetFieldNull(fieldIndex);
     640           1 :                 else if (len != odbc::ResultSet::UNKNOWN_LENGTH)
     641             :                 {
     642           1 :                     EnsureBufferCapacity(len);
     643           1 :                     resultSet_->getBinaryData(paramIndex, dataBuffer_.data(),
     644             :                                               len);
     645           1 :                     featWriter.SetFieldValue(fieldIndex, dataBuffer_.data(),
     646             :                                              len);
     647             :                 }
     648             :                 else
     649             :                 {
     650           0 :                     odbc::Binary binData = resultSet_->getBinary(paramIndex);
     651           0 :                     featWriter.SetFieldValue(fieldIndex, binData);
     652             :                 }
     653             :             }
     654           1 :             break;
     655           1 :             case odbc::SQLDataTypes::Date:
     656             :             case odbc::SQLDataTypes::TypeDate:
     657             :             {
     658           1 :                 odbc::Date date = resultSet_->getDate(paramIndex);
     659           1 :                 featWriter.SetFieldValue(fieldIndex, date);
     660             :             }
     661           1 :             break;
     662           1 :             case odbc::SQLDataTypes::Time:
     663             :             case odbc::SQLDataTypes::TypeTime:
     664             :             {
     665           1 :                 odbc::Time time = resultSet_->getTime(paramIndex);
     666           1 :                 featWriter.SetFieldValue(fieldIndex, time);
     667             :             }
     668           1 :             break;
     669           4 :             case odbc::SQLDataTypes::Timestamp:
     670             :             case odbc::SQLDataTypes::TypeTimestamp:
     671             :             {
     672             :                 odbc::Timestamp timestamp =
     673           4 :                     resultSet_->getTimestamp(paramIndex);
     674           4 :                 featWriter.SetFieldValue(fieldIndex, timestamp);
     675             :             }
     676           4 :             break;
     677           0 :             default:
     678           0 :                 break;
     679             :         }
     680             :     }
     681             : 
     682         543 :     return feature.release();
     683             : }
     684             : 
     685             : /************************************************************************/
     686             : /*                      InitFeatureDefinition()                         */
     687             : /************************************************************************/
     688             : 
     689          51 : OGRErr OGRHanaLayer::InitFeatureDefinition(const CPLString &schemaName,
     690             :                                            const CPLString &tableName,
     691             :                                            const CPLString &query,
     692             :                                            const CPLString &featureDefName)
     693             : {
     694          51 :     attrColumns_.clear();
     695          51 :     geomColumns_.clear();
     696          51 :     fidFieldIndex_ = OGRNullFID;
     697          51 :     fidFieldName_.clear();
     698          51 :     featureDefn_ = new OGRFeatureDefn(featureDefName.c_str());
     699          51 :     featureDefn_->Reference();
     700             : 
     701         102 :     std::vector<ColumnDescription> columnDescriptions;
     702             :     OGRErr err =
     703          51 :         dataSource_->GetQueryColumns(schemaName, query, columnDescriptions);
     704          51 :     if (err != OGRERR_NONE)
     705           0 :         return err;
     706             : 
     707             :     std::vector<CPLString> primKeys =
     708          51 :         dataSource_->GetTablePrimaryKeys(schemaName, tableName);
     709             : 
     710          51 :     if (featureDefn_->GetGeomFieldCount() == 1)
     711          51 :         featureDefn_->DeleteGeomFieldDefn(0);
     712             : 
     713         239 :     for (const ColumnDescription &clmDesc : columnDescriptions)
     714             :     {
     715         188 :         if (clmDesc.isGeometry)
     716             :         {
     717          32 :             const GeometryColumnDescription &geometryColumnDesc =
     718             :                 clmDesc.geometryDescription;
     719             : 
     720             :             auto geomFieldDefn = std::make_unique<OGRGeomFieldDefn>(
     721          64 :                 geometryColumnDesc.name.c_str(), geometryColumnDesc.type);
     722          32 :             geomFieldDefn->SetNullable(geometryColumnDesc.isNullable);
     723             : 
     724          32 :             if (geometryColumnDesc.srid >= 0)
     725             :             {
     726             :                 OGRSpatialReference *srs =
     727          29 :                     dataSource_->GetSrsById(geometryColumnDesc.srid);
     728          29 :                 geomFieldDefn->SetSpatialRef(srs);
     729          29 :                 srs->Release();
     730             :             }
     731          32 :             geomColumns_.push_back(geometryColumnDesc);
     732          32 :             featureDefn_->AddGeomFieldDefn(std::move(geomFieldDefn));
     733          32 :             continue;
     734             :         }
     735             : 
     736             :         AttributeColumnDescription attributeColumnDesc =
     737         312 :             clmDesc.attributeDescription;
     738         312 :         auto field = CreateFieldDefn(attributeColumnDesc);
     739             : 
     740         260 :         if ((field->GetType() == OFTInteger ||
     741         312 :              field->GetType() == OFTInteger64) &&
     742          76 :             (fidFieldIndex_ == OGRNullFID && primKeys.size() > 0))
     743             :         {
     744         410 :             for (const CPLString &key : primKeys)
     745             :             {
     746         407 :                 if (key.compare(attributeColumnDesc.name) == 0)
     747             :                 {
     748          44 :                     fidFieldIndex_ = static_cast<int>(attrColumns_.size());
     749          44 :                     fidFieldName_ = field->GetNameRef();
     750          44 :                     attributeColumnDesc.isFeatureID = true;
     751          44 :                     break;
     752             :                 }
     753             :             }
     754             :         }
     755             : 
     756         156 :         if (!attributeColumnDesc.isFeatureID)
     757         112 :             featureDefn_->AddFieldDefn(field.get());
     758         156 :         attrColumns_.push_back(attributeColumnDesc);
     759             :     }
     760             : 
     761          51 :     return OGRERR_NONE;
     762             : }
     763             : 
     764             : /************************************************************************/
     765             : /*                         ReadGeometryExtent()                         */
     766             : /************************************************************************/
     767             : 
     768          11 : void OGRHanaLayer::ReadGeometryExtent(int geomField, OGREnvelope *extent)
     769             : {
     770          11 :     EnsureInitialized();
     771             : 
     772          11 :     OGRGeomFieldDefn *geomFieldDef = featureDefn_->GetGeomFieldDefn(geomField);
     773          11 :     const char *clmName = geomFieldDef->GetNameRef();
     774          11 :     int srid = GetGeometryColumnSrid(geomField);
     775          22 :     CPLString sql;
     776          11 :     if (dataSource_->IsSrsRoundEarth(srid))
     777             :     {
     778           2 :         CPLString quotedClmName = QuotedIdentifier(clmName);
     779           1 :         bool hasSrsPlanarEquivalent = dataSource_->HasSrsPlanarEquivalent(srid);
     780             :         CPLString geomColumn =
     781           1 :             !hasSrsPlanarEquivalent
     782             :                 ? quotedClmName
     783           2 :                 : CPLString().Printf("%s.ST_SRID(%d)", quotedClmName.c_str(),
     784           3 :                                      ToPlanarSRID(srid));
     785           1 :         CPLString columns = CPLString().Printf(
     786             :             "MIN(%s.ST_XMin()), MIN(%s.ST_YMin()), MAX(%s.ST_XMax()), "
     787             :             "MAX(%s.ST_YMax())",
     788             :             geomColumn.c_str(), geomColumn.c_str(), geomColumn.c_str(),
     789           1 :             geomColumn.c_str());
     790           1 :         sql = BuildQuery(rawQuery_.c_str(), columns.c_str());
     791             :     }
     792             :     else
     793             :     {
     794          10 :         CPLString columns = CPLString().Printf(
     795          30 :             "ST_EnvelopeAggr(%s) AS ext", QuotedIdentifier(clmName).c_str());
     796          10 :         CPLString subQuery = BuildQuery(rawQuery_.c_str(), columns);
     797          20 :         sql = CPLString().Printf(
     798             :             "SELECT ext.ST_XMin(),ext.ST_YMin(),ext.ST_XMax(),ext.ST_YMax() "
     799             :             "FROM (%s)",
     800          10 :             subQuery.c_str());
     801             :     }
     802             : 
     803          11 :     extent->MinX = 0.0;
     804          11 :     extent->MaxX = 0.0;
     805          11 :     extent->MinY = 0.0;
     806          11 :     extent->MaxY = 0.0;
     807             : 
     808          22 :     odbc::StatementRef stmt = dataSource_->CreateStatement();
     809          22 :     odbc::ResultSetRef rsExtent = stmt->executeQuery(sql.c_str());
     810          11 :     if (rsExtent->next())
     811             :     {
     812          11 :         odbc::Double val = rsExtent->getDouble(1);
     813          11 :         if (!val.isNull())
     814             :         {
     815          11 :             extent->MinX = *val;
     816          11 :             extent->MinY = *rsExtent->getDouble(2);
     817          11 :             extent->MaxX = *rsExtent->getDouble(3);
     818          11 :             extent->MaxY = *rsExtent->getDouble(4);
     819             :         }
     820             :     }
     821          11 :     rsExtent->close();
     822          11 : }
     823             : 
     824             : /************************************************************************/
     825             : /*                          ResetReading()                              */
     826             : /************************************************************************/
     827             : 
     828         279 : void OGRHanaLayer::ResetReading()
     829             : {
     830         279 :     nextFeatureId_ = 0;
     831         279 :     resultSet_.reset();
     832         279 : }
     833             : 
     834             : /************************************************************************/
     835             : /*                            GetExtent()                               */
     836             : /************************************************************************/
     837             : 
     838          15 : OGRErr OGRHanaLayer::GetExtent(int iGeomField, OGREnvelope *extent, int force)
     839             : {
     840          26 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
     841          11 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
     842             :     {
     843           4 :         extent->MinX = 0.0;
     844           4 :         extent->MaxX = 0.0;
     845           4 :         extent->MinY = 0.0;
     846           4 :         extent->MaxY = 0.0;
     847             : 
     848           4 :         if (iGeomField != 0)
     849             :         {
     850           4 :             CPLError(CE_Failure, CPLE_AppDefined,
     851             :                      "Invalid geometry field index : %d", iGeomField);
     852             :         }
     853           4 :         return OGRERR_FAILURE;
     854             :     }
     855             : 
     856             :     try
     857             :     {
     858          11 :         ReadGeometryExtent(iGeomField, extent);
     859          11 :         return OGRERR_NONE;
     860             :     }
     861           0 :     catch (const std::exception &ex)
     862             :     {
     863             :         CPLString clmName =
     864           0 :             (iGeomField < static_cast<int>(geomColumns_.size()))
     865           0 :                 ? geomColumns_[static_cast<std::size_t>(geomColumns_.size())]
     866           0 :                       .name
     867           0 :                 : "unknown column";
     868           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     869             :                  "Unable to query extent of '%s' using fast method: %s",
     870           0 :                  clmName.c_str(), ex.what());
     871             :     }
     872             : 
     873           0 :     if (iGeomField == 0)
     874           0 :         return OGRLayer::GetExtent(extent, force);
     875             :     else
     876           0 :         return OGRLayer::GetExtent(iGeomField, extent, force);
     877             : }
     878             : 
     879             : /************************************************************************/
     880             : /*                            GetFeatureCount()                         */
     881             : /************************************************************************/
     882             : 
     883          53 : GIntBig OGRHanaLayer::GetFeatureCount(CPL_UNUSED int force)
     884             : {
     885          53 :     EnsureInitialized();
     886             : 
     887          53 :     GIntBig ret = 0;
     888          53 :     CPLString sql = CPLString().Printf("SELECT COUNT(*) FROM (%s) AS tmp",
     889         106 :                                        GetQueryStatement().c_str());
     890         106 :     odbc::StatementRef stmt = dataSource_->CreateStatement();
     891          53 :     odbc::ResultSetRef rs = stmt->executeQuery(sql.c_str());
     892          53 :     if (rs->next())
     893          53 :         ret = *rs->getLong(1);
     894          53 :     rs->close();
     895         106 :     return ret;
     896             : }
     897             : 
     898             : /************************************************************************/
     899             : /*                           GetLayerDefn()                             */
     900             : /************************************************************************/
     901             : 
     902         417 : OGRFeatureDefn *OGRHanaLayer::GetLayerDefn()
     903             : {
     904         417 :     EnsureInitialized();
     905         417 :     return featureDefn_;
     906             : }
     907             : 
     908             : /************************************************************************/
     909             : /*                               GetName()                              */
     910             : /************************************************************************/
     911             : 
     912           2 : const char *OGRHanaLayer::GetName()
     913             : {
     914           2 :     return GetDescription();
     915             : }
     916             : 
     917             : /************************************************************************/
     918             : /*                         GetNextFeature()                             */
     919             : /************************************************************************/
     920             : 
     921         597 : OGRFeature *OGRHanaLayer::GetNextFeature()
     922             : {
     923         597 :     EnsureInitialized();
     924             : 
     925             :     while (true)
     926             :     {
     927         597 :         OGRFeature *feature = GetNextFeatureInternal();
     928         597 :         if (feature == nullptr)
     929          54 :             return nullptr;
     930             : 
     931        1179 :         if ((m_poFilterGeom == nullptr ||
     932        1086 :              FilterGeometry(feature->GetGeometryRef())) &&
     933         543 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(feature)))
     934         543 :             return feature;
     935             : 
     936           0 :         delete feature;
     937           0 :     }
     938             : }
     939             : 
     940             : /************************************************************************/
     941             : /*                            GetFIDColumn()                            */
     942             : /************************************************************************/
     943             : 
     944          95 : const char *OGRHanaLayer::GetFIDColumn()
     945             : {
     946          95 :     EnsureInitialized();
     947          95 :     return fidFieldName_.c_str();
     948             : }
     949             : 
     950             : /************************************************************************/
     951             : /*                         SetAttributeFilter()                         */
     952             : /************************************************************************/
     953             : 
     954         101 : OGRErr OGRHanaLayer::SetAttributeFilter(const char *pszQuery)
     955             : {
     956         101 :     CPLFree(m_pszAttrQueryString);
     957         101 :     m_pszAttrQueryString = pszQuery ? CPLStrdup(pszQuery) : nullptr;
     958             : 
     959         101 :     if (pszQuery == nullptr || strlen(pszQuery) == 0)
     960          69 :         attrFilter_ = "";
     961             :     else
     962          32 :         attrFilter_.assign(pszQuery, strlen(pszQuery));
     963             : 
     964         101 :     ClearQueryStatement();
     965         101 :     BuildWhereClause();
     966         101 :     ResetReading();
     967             : 
     968         101 :     return OGRERR_NONE;
     969             : }
     970             : 
     971             : /************************************************************************/
     972             : /*                          SetSpatialFilter()                          */
     973             : /************************************************************************/
     974             : 
     975          78 : void OGRHanaLayer::SetSpatialFilter(int iGeomField, OGRGeometry *poGeom)
     976             : {
     977          78 :     m_iGeomFieldFilter = 0;
     978             : 
     979          78 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount())
     980             :     {
     981           4 :         CPLError(CE_Failure, CPLE_AppDefined,
     982             :                  "Invalid geometry field index : %d", iGeomField);
     983           4 :         return;
     984             :     }
     985          74 :     m_iGeomFieldFilter = iGeomField;
     986             : 
     987          74 :     if (!InstallFilter(poGeom))
     988          54 :         return;
     989             : 
     990          20 :     ClearQueryStatement();
     991          20 :     BuildWhereClause();
     992          20 :     ResetReading();
     993             : }
     994             : 
     995             : }  // namespace OGRHANA

Generated by: LCOV version 1.14