LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/odbc - ogrodbclayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 150 0.0 %
Date: 2026-02-27 12:28:37 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRODBCLayer class, code shared between
       5             :  *           the direct table access, and the generic SQL results.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : #include "ogr_odbc.h"
      16             : #include "cpl_string.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <cmath>
      20             : 
      21             : /************************************************************************/
      22             : /*                            OGRODBCLayer()                            */
      23             : /************************************************************************/
      24             : 
      25           0 : OGRODBCLayer::OGRODBCLayer()
      26             :     : poFeatureDefn(nullptr), poStmt(nullptr), poSRS(nullptr),
      27             :       nSRSId(-2),  // Have not queried the database for it yet.
      28             :       iNextShapeId(0), poDS(nullptr), bGeomColumnWKB(FALSE),
      29           0 :       pszGeomColumn(nullptr), pszFIDColumn(nullptr), panFieldOrdinals(nullptr)
      30             : {
      31           0 : }
      32             : 
      33             : /************************************************************************/
      34             : /*                           ~OGRODBCLayer()                            */
      35             : /************************************************************************/
      36             : 
      37           0 : OGRODBCLayer::~OGRODBCLayer()
      38             : 
      39             : {
      40           0 :     if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr)
      41             :     {
      42           0 :         CPLDebug("OGR_ODBC", "%d features read on layer '%s'.",
      43           0 :                  (int)m_nFeaturesRead, poFeatureDefn->GetName());
      44             :     }
      45             : 
      46           0 :     if (poStmt)
      47             :     {
      48           0 :         delete poStmt;
      49           0 :         poStmt = nullptr;
      50             :     }
      51             : 
      52           0 :     if (pszGeomColumn)
      53           0 :         CPLFree(pszGeomColumn);
      54             : 
      55           0 :     if (panFieldOrdinals)
      56           0 :         CPLFree(panFieldOrdinals);
      57             : 
      58           0 :     if (poFeatureDefn)
      59             :     {
      60           0 :         poFeatureDefn->Release();
      61           0 :         poFeatureDefn = nullptr;
      62             :     }
      63             : 
      64           0 :     if (poSRS)
      65           0 :         poSRS->Release();
      66           0 : }
      67             : 
      68             : /************************************************************************/
      69             : /*                          BuildFeatureDefn()                          */
      70             : /*                                                                      */
      71             : /*      Build feature definition from a set of column definitions       */
      72             : /*      set on a statement.  Sift out geometry and FID fields.          */
      73             : /************************************************************************/
      74             : 
      75           0 : CPLErr OGRODBCLayer::BuildFeatureDefn(const char *pszLayerName,
      76             :                                       CPLODBCStatement *poStmtIn)
      77             : 
      78             : {
      79           0 :     poFeatureDefn = new OGRFeatureDefn(pszLayerName);
      80           0 :     SetDescription(poFeatureDefn->GetName());
      81           0 :     int nRawColumns = poStmtIn->GetColCount();
      82             : 
      83           0 :     poFeatureDefn->Reference();
      84             : 
      85           0 :     panFieldOrdinals = (int *)CPLMalloc(sizeof(int) * nRawColumns);
      86             : 
      87           0 :     for (int iCol = 0; iCol < nRawColumns; iCol++)
      88             :     {
      89           0 :         OGRFieldDefn oField(poStmtIn->GetColName(iCol), OFTString);
      90             : 
      91           0 :         oField.SetWidth(std::max<int>(0, poStmtIn->GetColSize(iCol)));
      92             : 
      93           0 :         if (pszGeomColumn != nullptr &&
      94           0 :             EQUAL(poStmtIn->GetColName(iCol), pszGeomColumn))
      95           0 :             continue;
      96             : 
      97           0 :         switch (CPLODBCStatement::GetTypeMapping(poStmtIn->GetColType(iCol)))
      98             :         {
      99           0 :             case SQL_C_SSHORT:
     100             :             case SQL_C_USHORT:
     101             :             case SQL_C_SLONG:
     102             :             case SQL_C_ULONG:
     103           0 :                 oField.SetType(OFTInteger);
     104           0 :                 break;
     105             : 
     106           0 :             case SQL_C_SBIGINT:
     107             :             case SQL_C_UBIGINT:
     108           0 :                 oField.SetType(OFTInteger64);
     109           0 :                 break;
     110             : 
     111           0 :             case SQL_C_BINARY:
     112           0 :                 oField.SetType(OFTBinary);
     113           0 :                 break;
     114             : 
     115           0 :             case SQL_C_NUMERIC:
     116           0 :                 oField.SetType(OFTReal);
     117           0 :                 oField.SetPrecision(poStmtIn->GetColPrecision(iCol));
     118           0 :                 break;
     119             : 
     120           0 :             case SQL_C_FLOAT:
     121             :             case SQL_C_DOUBLE:
     122           0 :                 oField.SetType(OFTReal);
     123           0 :                 oField.SetWidth(0);
     124           0 :                 break;
     125             : 
     126           0 :             case SQL_C_DATE:
     127           0 :                 oField.SetType(OFTDate);
     128           0 :                 break;
     129             : 
     130           0 :             case SQL_C_TIME:
     131           0 :                 oField.SetType(OFTTime);
     132           0 :                 break;
     133             : 
     134           0 :             case SQL_C_TIMESTAMP:
     135             :             case SQL_C_TYPE_TIMESTAMP:
     136           0 :                 oField.SetType(OFTDateTime);
     137           0 :                 break;
     138             : 
     139           0 :             default:
     140             :                 /* leave it as OFTString */;
     141             :         }
     142             : 
     143           0 :         poFeatureDefn->AddFieldDefn(&oField);
     144           0 :         panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol + 1;
     145             :     }
     146             : 
     147             :     /* -------------------------------------------------------------------- */
     148             :     /*      If we don't already have an FID, check if there is a special    */
     149             :     /*      FID named column available.                                     */
     150             :     /* -------------------------------------------------------------------- */
     151           0 :     if (pszFIDColumn == nullptr)
     152             :     {
     153           0 :         const char *pszOGR_FID = CPLGetConfigOption("ODBC_OGR_FID", "OGR_FID");
     154           0 :         if (poFeatureDefn->GetFieldIndex(pszOGR_FID) != -1)
     155           0 :             pszFIDColumn = CPLStrdup(pszOGR_FID);
     156             :     }
     157             : 
     158           0 :     if (pszFIDColumn != nullptr)
     159           0 :         CPLDebug("OGR_ODBC", "Using column %s as FID for table %s.",
     160           0 :                  pszFIDColumn, poFeatureDefn->GetName());
     161             :     else
     162           0 :         CPLDebug("OGR_ODBC", "Table %s has no identified FID column.",
     163           0 :                  poFeatureDefn->GetName());
     164             : 
     165           0 :     return CE_None;
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                            ResetReading()                            */
     170             : /************************************************************************/
     171             : 
     172           0 : void OGRODBCLayer::ResetReading()
     173             : 
     174             : {
     175           0 :     iNextShapeId = 0;
     176           0 :     m_bEOF = false;
     177           0 : }
     178             : 
     179             : /************************************************************************/
     180             : /*                           GetNextFeature()                           */
     181             : /************************************************************************/
     182             : 
     183           0 : OGRFeature *OGRODBCLayer::GetNextFeature()
     184             : 
     185             : {
     186             :     while (true)
     187             :     {
     188           0 :         OGRFeature *poFeature = GetNextRawFeature();
     189           0 :         if (poFeature == nullptr)
     190           0 :             return nullptr;
     191             : 
     192           0 :         if ((m_poFilterGeom == nullptr ||
     193           0 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     194           0 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     195           0 :             return poFeature;
     196             : 
     197           0 :         delete poFeature;
     198           0 :     }
     199             : }
     200             : 
     201             : /************************************************************************/
     202             : /*                         GetNextRawFeature()                          */
     203             : /************************************************************************/
     204             : 
     205           0 : OGRFeature *OGRODBCLayer::GetNextRawFeature()
     206             : 
     207             : {
     208           0 :     if (m_bEOF || GetStatement() == nullptr)
     209           0 :         return nullptr;
     210             : 
     211             :     /* -------------------------------------------------------------------- */
     212             :     /*      If we are marked to restart then do so, and fetch a record.     */
     213             :     /* -------------------------------------------------------------------- */
     214           0 :     if (!poStmt->Fetch())
     215             :     {
     216           0 :         delete poStmt;
     217           0 :         poStmt = nullptr;
     218           0 :         m_bEOF = true;
     219           0 :         return nullptr;
     220             :     }
     221             : 
     222             :     /* -------------------------------------------------------------------- */
     223             :     /*      Create a feature from the current result.                       */
     224             :     /* -------------------------------------------------------------------- */
     225           0 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     226             : 
     227           0 :     if (pszFIDColumn != nullptr && poStmt->GetColId(pszFIDColumn) > -1)
     228           0 :         poFeature->SetFID(
     229           0 :             atoi(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))));
     230             :     else
     231           0 :         poFeature->SetFID(iNextShapeId);
     232             : 
     233           0 :     iNextShapeId++;
     234           0 :     m_nFeaturesRead++;
     235             : 
     236             :     /* -------------------------------------------------------------------- */
     237             :     /*      Set the fields.                                                 */
     238             :     /* -------------------------------------------------------------------- */
     239           0 :     for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
     240             :     {
     241             :         const OGRFieldType eType =
     242           0 :             poFeatureDefn->GetFieldDefn(iField)->GetType();
     243           0 :         int iSrcField = panFieldOrdinals[iField] - 1;
     244             : 
     245           0 :         if (eType == OFTReal &&
     246           0 :             (poStmt->Flags() &
     247             :              CPLODBCStatement::Flag::RetrieveNumericColumnsAsDouble))
     248             :         {
     249             :             // for OFTReal fields we retrieve the value directly as a double
     250             :             // to avoid loss of precision associated with double/float->string
     251             :             // conversion
     252           0 :             const double dfValue = poStmt->GetColDataAsDouble(iSrcField);
     253           0 :             if (std::isnan(dfValue))
     254             :             {
     255           0 :                 poFeature->SetFieldNull(iField);
     256             :             }
     257             :             else
     258             :             {
     259           0 :                 poFeature->SetField(iField, dfValue);
     260             :             }
     261             :         }
     262             :         else
     263             :         {
     264           0 :             const char *pszValue = poStmt->GetColData(iSrcField);
     265             : 
     266           0 :             if (pszValue == nullptr)
     267           0 :                 poFeature->SetFieldNull(iField);
     268           0 :             else if (poFeature->GetFieldDefnRef(iField)->GetType() == OFTBinary)
     269           0 :                 poFeature->SetField(iField, poStmt->GetColDataLength(iSrcField),
     270             :                                     (GByte *)pszValue);
     271             :             else
     272           0 :                 poFeature->SetField(iField, pszValue);
     273             :         }
     274             :     }
     275             : 
     276             :     /* -------------------------------------------------------------------- */
     277             :     /*      Try to extract a geometry.                                      */
     278             :     /* -------------------------------------------------------------------- */
     279           0 :     if (pszGeomColumn != nullptr)
     280             :     {
     281           0 :         int iField = poStmt->GetColId(pszGeomColumn);
     282           0 :         const char *pszGeomText = poStmt->GetColData(iField);
     283           0 :         OGRGeometry *poGeom = nullptr;
     284           0 :         OGRErr eErr = OGRERR_NONE;
     285             : 
     286           0 :         if (pszGeomText != nullptr && !bGeomColumnWKB)
     287             :         {
     288           0 :             eErr = OGRGeometryFactory::createFromWkt(pszGeomText, nullptr,
     289             :                                                      &poGeom);
     290             :         }
     291           0 :         else if (pszGeomText != nullptr && bGeomColumnWKB)
     292             :         {
     293           0 :             int nLength = poStmt->GetColDataLength(iField);
     294             : 
     295           0 :             eErr = OGRGeometryFactory::createFromWkb(pszGeomText, nullptr,
     296             :                                                      &poGeom, nLength);
     297             :         }
     298             : 
     299           0 :         if (eErr != OGRERR_NONE)
     300             :         {
     301           0 :             const char *pszMessage = nullptr;
     302             : 
     303           0 :             switch (eErr)
     304             :             {
     305           0 :                 case OGRERR_NOT_ENOUGH_DATA:
     306           0 :                     pszMessage = "Not enough data to deserialize";
     307           0 :                     break;
     308           0 :                 case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
     309           0 :                     pszMessage = "Unsupported geometry type";
     310           0 :                     break;
     311           0 :                 case OGRERR_CORRUPT_DATA:
     312           0 :                     pszMessage = "Corrupt data";
     313           0 :                     break;
     314           0 :                 default:
     315           0 :                     pszMessage = "Unrecognized error";
     316             :             }
     317           0 :             CPLError(CE_Failure, CPLE_AppDefined, "GetNextRawFeature(): %s",
     318             :                      pszMessage);
     319             :         }
     320             : 
     321           0 :         if (poGeom != nullptr)
     322           0 :             poFeature->SetGeometryDirectly(poGeom);
     323             :     }
     324             : 
     325           0 :     return poFeature;
     326             : }
     327             : 
     328             : /************************************************************************/
     329             : /*                             GetFeature()                             */
     330             : /************************************************************************/
     331             : 
     332           0 : OGRFeature *OGRODBCLayer::GetFeature(GIntBig nFeatureId)
     333             : 
     334             : {
     335             :     /* This should be implemented directly! */
     336             : 
     337           0 :     return OGRLayer::GetFeature(nFeatureId);
     338             : }
     339             : 
     340             : /************************************************************************/
     341             : /*                           TestCapability()                           */
     342             : /************************************************************************/
     343             : 
     344           0 : int OGRODBCLayer::TestCapability(const char *) const
     345             : {
     346           0 :     return FALSE;
     347             : }
     348             : 
     349             : /************************************************************************/
     350             : /*                           GetSpatialRef()                            */
     351             : /************************************************************************/
     352             : 
     353           0 : const OGRSpatialReference *OGRODBCLayer::GetSpatialRef() const
     354             : 
     355             : {
     356           0 :     return poSRS;
     357             : }

Generated by: LCOV version 1.14