LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vrt - ogrvrtlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1137 1230 92.4 %
Date: 2025-01-18 12:42:00 Functions: 37 37 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRVRTLayer class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogr_vrt.h"
      16             : 
      17             : #include <cassert>
      18             : #include <cmath>
      19             : #include <cstddef>
      20             : #include <cstdio>
      21             : #include <cstdlib>
      22             : #include <cstring>
      23             : #include <limits>
      24             : #include <string>
      25             : #include <vector>
      26             : 
      27             : #include "cpl_conv.h"
      28             : #include "cpl_error.h"
      29             : #include "cpl_minixml.h"
      30             : #include "cpl_string.h"
      31             : #include "gdal.h"
      32             : #include "gdal_priv.h"
      33             : #include "ogr_api.h"
      34             : #include "ogr_core.h"
      35             : #include "ogr_feature.h"
      36             : #include "ogr_geometry.h"
      37             : #include "ogr_spatialref.h"
      38             : #include "ogrpgeogeometry.h"
      39             : #include "ogrsf_frmts.h"
      40             : #include "ogrvrtgeometrytypes.h"
      41             : 
      42             : #define UNSUPPORTED_OP_READ_ONLY                                               \
      43             :     "%s : unsupported operation on a read-only datasource."
      44             : 
      45             : /************************************************************************/
      46             : /*                   GetFieldIndexCaseSensitiveFirst()                  */
      47             : /************************************************************************/
      48             : 
      49        2683 : static int GetFieldIndexCaseSensitiveFirst(OGRFeatureDefn *poFDefn,
      50             :                                            const char *pszFieldName)
      51             : {
      52        2683 :     int idx = poFDefn->GetFieldIndexCaseSensitive(pszFieldName);
      53        2683 :     if (idx < 0)
      54         779 :         idx = poFDefn->GetFieldIndex(pszFieldName);
      55        2683 :     return idx;
      56             : }
      57             : 
      58             : /************************************************************************/
      59             : /*                       OGRVRTGeomFieldProps()                         */
      60             : /************************************************************************/
      61             : 
      62         797 : OGRVRTGeomFieldProps::OGRVRTGeomFieldProps()
      63             :     : eGeomType(wkbUnknown), poSRS(nullptr), bSrcClip(false),
      64             :       poSrcRegion(nullptr), eGeometryStyle(VGS_Direct), iGeomField(-1),
      65             :       iGeomXField(-1), iGeomYField(-1), iGeomZField(-1), iGeomMField(-1),
      66         797 :       bReportSrcColumn(true), bUseSpatialSubquery(false), bNullable(true)
      67             : {
      68         797 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                      ~OGRVRTGeomFieldProps()                         */
      72             : /************************************************************************/
      73             : 
      74         797 : OGRVRTGeomFieldProps::~OGRVRTGeomFieldProps()
      75             : {
      76         797 :     if (poSRS != nullptr)
      77         555 :         const_cast<OGRSpatialReference *>(poSRS)->Release();
      78         797 :     if (poSrcRegion != nullptr)
      79          11 :         delete poSrcRegion;
      80         797 : }
      81             : 
      82             : /************************************************************************/
      83             : /*                            OGRVRTLayer()                             */
      84             : /************************************************************************/
      85             : 
      86         906 : OGRVRTLayer::OGRVRTLayer(OGRVRTDataSource *poDSIn)
      87             :     : poDS(poDSIn), bHasFullInitialized(false), psLTree(nullptr),
      88             :       poFeatureDefn(nullptr), poSrcDS(nullptr), poSrcLayer(nullptr),
      89             :       poSrcFeatureDefn(nullptr), bNeedReset(true), bSrcLayerFromSQL(false),
      90             :       bSrcDSShared(false), bAttrFilterPassThrough(false),
      91             :       pszAttrFilter(nullptr), iFIDField(-1),  // -1 means pass through.
      92             :       iStyleField(-1),                        // -1 means pass through.
      93         906 :       bUpdate(false), nFeatureCount(-1), bError(false)
      94             : {
      95         906 : }
      96             : 
      97             : /************************************************************************/
      98             : /*                            ~OGRVRTLayer()                            */
      99             : /************************************************************************/
     100             : 
     101        1812 : OGRVRTLayer::~OGRVRTLayer()
     102             : 
     103             : {
     104         906 :     if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr)
     105             :     {
     106         246 :         CPLDebug("VRT", "%d features read on layer '%s'.",
     107         123 :                  static_cast<int>(m_nFeaturesRead), poFeatureDefn->GetName());
     108             :     }
     109             : 
     110        1561 :     for (size_t i = 0; i < apoGeomFieldProps.size(); i++)
     111         655 :         delete apoGeomFieldProps[i];
     112             : 
     113         906 :     if (poSrcDS != nullptr)
     114             :     {
     115         435 :         if (poSrcLayer)
     116             :         {
     117         432 :             poSrcLayer->SetIgnoredFields(nullptr);
     118         432 :             poSrcLayer->SetAttributeFilter(nullptr);
     119         432 :             poSrcLayer->SetSpatialFilter(nullptr);
     120             :         }
     121             : 
     122         435 :         if (bSrcLayerFromSQL && poSrcLayer)
     123           2 :             poSrcDS->ReleaseResultSet(poSrcLayer);
     124             : 
     125         435 :         GDALClose((GDALDatasetH)poSrcDS);
     126             :     }
     127             : 
     128         906 :     if (poFeatureDefn)
     129         499 :         poFeatureDefn->Release();
     130             : 
     131         906 :     CPLFree(pszAttrFilter);
     132        1812 : }
     133             : 
     134             : /************************************************************************/
     135             : /*                         GetSrcLayerDefn()                            */
     136             : /************************************************************************/
     137             : 
     138       46677 : OGRFeatureDefn *OGRVRTLayer::GetSrcLayerDefn()
     139             : {
     140       46677 :     if (poSrcFeatureDefn)
     141       46246 :         return poSrcFeatureDefn;
     142             : 
     143         431 :     if (poSrcLayer)
     144         431 :         poSrcFeatureDefn = poSrcLayer->GetLayerDefn();
     145             : 
     146         431 :     return poSrcFeatureDefn;
     147             : }
     148             : 
     149             : /************************************************************************/
     150             : /*                         FastInitialize()                             */
     151             : /************************************************************************/
     152             : 
     153         906 : bool OGRVRTLayer::FastInitialize(CPLXMLNode *psLTreeIn,
     154             :                                  const char *pszVRTDirectory, int bUpdateIn)
     155             : 
     156             : {
     157         906 :     psLTree = psLTreeIn;
     158         906 :     bUpdate = CPL_TO_BOOL(bUpdateIn);
     159         906 :     osVRTDirectory = pszVRTDirectory;
     160             : 
     161         906 :     if (!EQUAL(psLTree->pszValue, "OGRVRTLayer"))
     162           0 :         return FALSE;
     163             : 
     164             :     // Get layer name.
     165         906 :     const char *pszLayerName = CPLGetXMLValue(psLTree, "name", nullptr);
     166             : 
     167         906 :     if (pszLayerName == nullptr)
     168             :     {
     169           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     170             :                  "Missing name attribute on OGRVRTLayer");
     171           1 :         return FALSE;
     172             :     }
     173             : 
     174         905 :     osName = pszLayerName;
     175         905 :     SetDescription(pszLayerName);
     176             : 
     177             :     // Do we have a fixed geometry type?  If so, use it.
     178         905 :     CPLXMLNode *psGeometryFieldNode = CPLGetXMLNode(psLTree, "GeometryField");
     179         905 :     const char *pszGType = CPLGetXMLValue(psLTree, "GeometryType", nullptr);
     180         905 :     if (pszGType == nullptr && psGeometryFieldNode != nullptr)
     181          31 :         pszGType = CPLGetXMLValue(psGeometryFieldNode, "GeometryType", nullptr);
     182         905 :     if (pszGType != nullptr)
     183             :     {
     184         361 :         int l_bError = FALSE;
     185             :         const OGRwkbGeometryType eGeomType =
     186         361 :             OGRVRTGetGeometryType(pszGType, &l_bError);
     187         361 :         if (l_bError)
     188             :         {
     189           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     190             :                      "GeometryType %s not recognised.", pszGType);
     191           1 :             return FALSE;
     192             :         }
     193         360 :         if (eGeomType != wkbNone)
     194             :         {
     195         353 :             apoGeomFieldProps.push_back(new OGRVRTGeomFieldProps());
     196         353 :             apoGeomFieldProps[0]->eGeomType = eGeomType;
     197             :         }
     198             :     }
     199             : 
     200             :     // Apply a spatial reference system if provided.
     201         904 :     const char *pszLayerSRS = CPLGetXMLValue(psLTree, "LayerSRS", nullptr);
     202         904 :     if (pszLayerSRS == nullptr && psGeometryFieldNode != nullptr)
     203         142 :         pszLayerSRS = CPLGetXMLValue(psGeometryFieldNode, "SRS", nullptr);
     204         904 :     if (pszLayerSRS != nullptr)
     205             :     {
     206         186 :         if (apoGeomFieldProps.empty())
     207             :         {
     208           3 :             apoGeomFieldProps.push_back(new OGRVRTGeomFieldProps());
     209             :         }
     210         186 :         if (!(EQUAL(pszLayerSRS, "NULL")))
     211             :         {
     212         186 :             OGRSpatialReference oSRS;
     213         186 :             oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     214             : 
     215         186 :             if (oSRS.SetFromUserInput(
     216             :                     pszLayerSRS,
     217             :                     OGRSpatialReference::
     218         186 :                         SET_FROM_USER_INPUT_LIMITATIONS_get()) != OGRERR_NONE)
     219             :             {
     220           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     221             :                          "Failed to import LayerSRS `%s'.", pszLayerSRS);
     222           1 :                 return FALSE;
     223             :             }
     224         185 :             apoGeomFieldProps[0]->poSRS = oSRS.Clone();
     225             :         }
     226             :     }
     227             : 
     228             :     // Set FeatureCount if provided.
     229             :     const char *pszFeatureCount =
     230         903 :         CPLGetXMLValue(psLTree, "FeatureCount", nullptr);
     231         903 :     if (pszFeatureCount != nullptr)
     232             :     {
     233           1 :         nFeatureCount = CPLAtoGIntBig(pszFeatureCount);
     234             :     }
     235             : 
     236             :     // Set Extent if provided.
     237         903 :     const char *pszExtentXMin = CPLGetXMLValue(psLTree, "ExtentXMin", nullptr);
     238         903 :     const char *pszExtentYMin = CPLGetXMLValue(psLTree, "ExtentYMin", nullptr);
     239         903 :     const char *pszExtentXMax = CPLGetXMLValue(psLTree, "ExtentXMax", nullptr);
     240         903 :     const char *pszExtentYMax = CPLGetXMLValue(psLTree, "ExtentYMax", nullptr);
     241         903 :     if (pszExtentXMin == nullptr && psGeometryFieldNode != nullptr)
     242             :     {
     243             :         pszExtentXMin =
     244         312 :             CPLGetXMLValue(psGeometryFieldNode, "ExtentXMin", nullptr);
     245             :         pszExtentYMin =
     246         312 :             CPLGetXMLValue(psGeometryFieldNode, "ExtentYMin", nullptr);
     247             :         pszExtentXMax =
     248         312 :             CPLGetXMLValue(psGeometryFieldNode, "ExtentXMax", nullptr);
     249             :         pszExtentYMax =
     250         312 :             CPLGetXMLValue(psGeometryFieldNode, "ExtentYMax", nullptr);
     251             :     }
     252         903 :     if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
     253           8 :         pszExtentXMax != nullptr && pszExtentYMax != nullptr)
     254             :     {
     255           8 :         if (apoGeomFieldProps.empty())
     256             :         {
     257           0 :             apoGeomFieldProps.push_back(new OGRVRTGeomFieldProps());
     258           0 :             assert(!apoGeomFieldProps.empty());
     259             :         }
     260           8 :         apoGeomFieldProps[0]->sStaticEnvelope.MinX = CPLAtof(pszExtentXMin);
     261           8 :         apoGeomFieldProps[0]->sStaticEnvelope.MinY = CPLAtof(pszExtentYMin);
     262           8 :         apoGeomFieldProps[0]->sStaticEnvelope.MaxX = CPLAtof(pszExtentXMax);
     263           8 :         apoGeomFieldProps[0]->sStaticEnvelope.MaxY = CPLAtof(pszExtentYMax);
     264             :     }
     265             : 
     266         903 :     return TRUE;
     267             : }
     268             : 
     269             : /************************************************************************/
     270             : /*                       ParseGeometryField()                           */
     271             : /************************************************************************/
     272             : 
     273         147 : bool OGRVRTLayer::ParseGeometryField(CPLXMLNode *psNode,
     274             :                                      CPLXMLNode *psNodeParent,
     275             :                                      OGRVRTGeomFieldProps *poProps)
     276             : {
     277         147 :     const char *pszName = CPLGetXMLValue(psNode, "name", nullptr);
     278         147 :     poProps->osName = pszName ? pszName : "";
     279         147 :     if (pszName == nullptr && apoGeomFieldProps.size() > 1 &&
     280           0 :         poProps != apoGeomFieldProps[0])
     281             :     {
     282           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     283             :                  "A 'name' attribute should be defined when there are "
     284             :                  "several geometry fields");
     285             :     }
     286             : 
     287             :     // Do we have a fixed geometry type?
     288         147 :     const char *pszGType = CPLGetXMLValue(psNode, "GeometryType", nullptr);
     289         147 :     if (pszGType == nullptr && poProps == apoGeomFieldProps[0])
     290         134 :         pszGType = CPLGetXMLValue(psNodeParent, "GeometryType", nullptr);
     291         147 :     if (pszGType != nullptr)
     292             :     {
     293         118 :         int l_bError = FALSE;
     294         118 :         poProps->eGeomType = OGRVRTGetGeometryType(pszGType, &l_bError);
     295         118 :         if (l_bError)
     296             :         {
     297           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     298             :                      "GeometryType %s not recognised.", pszGType);
     299           0 :             return false;
     300             :         }
     301             :     }
     302             : 
     303             :     // Determine which field(s) to get the geometry from.
     304         147 :     const char *pszEncoding = CPLGetXMLValue(psNode, "encoding", "direct");
     305             : 
     306         147 :     if (EQUAL(pszEncoding, "Direct"))
     307          30 :         poProps->eGeometryStyle = VGS_Direct;
     308         117 :     else if (EQUAL(pszEncoding, "None"))
     309           0 :         poProps->eGeometryStyle = VGS_None;
     310         117 :     else if (EQUAL(pszEncoding, "WKT"))
     311          52 :         poProps->eGeometryStyle = VGS_WKT;
     312          65 :     else if (EQUAL(pszEncoding, "WKB"))
     313           1 :         poProps->eGeometryStyle = VGS_WKB;
     314          64 :     else if (EQUAL(pszEncoding, "Shape"))
     315           1 :         poProps->eGeometryStyle = VGS_Shape;
     316          63 :     else if (EQUAL(pszEncoding, "PointFromColumns"))
     317             :     {
     318          62 :         poProps->eGeometryStyle = VGS_PointFromColumns;
     319          62 :         poProps->bUseSpatialSubquery = CPLTestBool(
     320             :             CPLGetXMLValue(psNode, "GeometryField.useSpatialSubquery", "TRUE"));
     321             : 
     322          62 :         poProps->iGeomXField = GetFieldIndexCaseSensitiveFirst(
     323             :             GetSrcLayerDefn(), CPLGetXMLValue(psNode, "x", "missing"));
     324          62 :         poProps->iGeomYField = GetFieldIndexCaseSensitiveFirst(
     325             :             GetSrcLayerDefn(), CPLGetXMLValue(psNode, "y", "missing"));
     326          62 :         poProps->iGeomZField = GetFieldIndexCaseSensitiveFirst(
     327             :             GetSrcLayerDefn(), CPLGetXMLValue(psNode, "z", "missing"));
     328          62 :         poProps->iGeomMField = GetFieldIndexCaseSensitiveFirst(
     329             :             GetSrcLayerDefn(), CPLGetXMLValue(psNode, "m", "missing"));
     330             : 
     331          62 :         if (poProps->iGeomXField == -1 || poProps->iGeomYField == -1)
     332             :         {
     333           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     334             :                      "Unable to identify source X or Y field for "
     335             :                      "PointFromColumns encoding.");
     336           1 :             return false;
     337             :         }
     338             : 
     339          61 :         if (pszGType == nullptr)
     340             :         {
     341           7 :             poProps->eGeomType = wkbPoint;
     342           7 :             if (poProps->iGeomZField != -1)
     343           1 :                 poProps->eGeomType = OGR_GT_SetZ(poProps->eGeomType);
     344           7 :             if (poProps->iGeomMField != -1)
     345           1 :                 poProps->eGeomType = OGR_GT_SetM(poProps->eGeomType);
     346             :         }
     347             :     }
     348             :     else
     349             :     {
     350           1 :         CPLError(CE_Failure, CPLE_AppDefined, "encoding=\"%s\" not recognised.",
     351             :                  pszEncoding);
     352           1 :         return false;
     353             :     }
     354             : 
     355         145 :     if (poProps->eGeometryStyle == VGS_WKT ||
     356          93 :         poProps->eGeometryStyle == VGS_WKB ||
     357          92 :         poProps->eGeometryStyle == VGS_Shape)
     358             :     {
     359          54 :         const char *pszFieldName = CPLGetXMLValue(psNode, "field", "missing");
     360             : 
     361          54 :         poProps->iGeomField =
     362          54 :             GetFieldIndexCaseSensitiveFirst(GetSrcLayerDefn(), pszFieldName);
     363             : 
     364          54 :         if (poProps->iGeomField == -1)
     365             :         {
     366           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     367             :                      "Unable to identify source field '%s' for geometry.",
     368             :                      pszFieldName);
     369           1 :             return false;
     370          53 :         }
     371             :     }
     372          91 :     else if (poProps->eGeometryStyle == VGS_Direct)
     373             :     {
     374          30 :         const char *pszFieldName = CPLGetXMLValue(psNode, "field", nullptr);
     375             : 
     376          53 :         if (pszFieldName != nullptr ||
     377          23 :             GetSrcLayerDefn()->GetGeomFieldCount() > 1)
     378             :         {
     379          13 :             if (pszFieldName == nullptr)
     380           6 :                 pszFieldName = poProps->osName;
     381          13 :             poProps->iGeomField =
     382          13 :                 GetSrcLayerDefn()->GetGeomFieldIndex(pszFieldName);
     383             : 
     384          13 :             if (poProps->iGeomField == -1)
     385             :             {
     386           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     387             :                          "Unable to identify source geometry field '%s' "
     388             :                          "for geometry.",
     389             :                          pszFieldName);
     390           1 :                 return false;
     391             :             }
     392             :         }
     393          17 :         else if (GetSrcLayerDefn()->GetGeomFieldCount() == 1)
     394             :         {
     395          17 :             poProps->iGeomField = 0;
     396             :         }
     397           0 :         else if (psNode != nullptr)
     398             :         {
     399           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     400             :                      "Unable to identify source geometry field.");
     401           0 :             return false;
     402             :         }
     403             :     }
     404             : 
     405         143 :     poProps->bReportSrcColumn =
     406         143 :         CPLTestBool(CPLGetXMLValue(psNode, "reportSrcColumn", "YES"));
     407             : 
     408             :     // Guess geometry type if not explicitly provided (or computed).
     409         143 :     if (pszGType == nullptr && poProps->eGeomType == wkbUnknown)
     410             :     {
     411          18 :         if (GetSrcLayerDefn()->GetGeomFieldCount() == 1)
     412           7 :             poProps->eGeomType = poSrcLayer->GetGeomType();
     413          11 :         else if (poProps->eGeometryStyle == VGS_Direct &&
     414           6 :                  poProps->iGeomField >= 0)
     415             :         {
     416          12 :             poProps->eGeomType = GetSrcLayerDefn()
     417           6 :                                      ->GetGeomFieldDefn(poProps->iGeomField)
     418           6 :                                      ->GetType();
     419             :         }
     420             :     }
     421             : 
     422             :     // Copy spatial reference system from source if not provided.
     423         143 :     const char *pszSRS = CPLGetXMLValue(psNode, "SRS", nullptr);
     424         143 :     if (pszSRS == nullptr && poProps == apoGeomFieldProps[0])
     425         131 :         pszSRS = CPLGetXMLValue(psNodeParent, "LayerSRS", nullptr);
     426         143 :     if (pszSRS == nullptr)
     427             :     {
     428          40 :         const OGRSpatialReference *poSRS = nullptr;
     429          40 :         if (GetSrcLayerDefn()->GetGeomFieldCount() == 1)
     430             :         {
     431          20 :             poSRS = poSrcLayer->GetSpatialRef();
     432             :         }
     433          20 :         else if (poProps->eGeometryStyle == VGS_Direct &&
     434           6 :                  poProps->iGeomField >= 0)
     435             :         {
     436           6 :             poSRS = GetSrcLayerDefn()
     437           6 :                         ->GetGeomFieldDefn(poProps->iGeomField)
     438           6 :                         ->GetSpatialRef();
     439             :         }
     440          40 :         if (poSRS != nullptr)
     441          11 :             poProps->poSRS = poSRS->Clone();
     442             :     }
     443         103 :     else if (poProps->poSRS == nullptr)
     444             :     {
     445          98 :         if (!(EQUAL(pszSRS, "NULL")))
     446             :         {
     447          98 :             OGRSpatialReference oSRS;
     448          98 :             oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     449             : 
     450          98 :             if (oSRS.SetFromUserInput(
     451             :                     pszSRS,
     452             :                     OGRSpatialReference::
     453          98 :                         SET_FROM_USER_INPUT_LIMITATIONS_get()) != OGRERR_NONE)
     454             :             {
     455           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     456             :                          "Failed to import SRS `%s'.", pszSRS);
     457           0 :                 return false;
     458             :             }
     459          98 :             poProps->poSRS = oSRS.Clone();
     460             :         }
     461             :     }
     462             : 
     463             :     // Do we have a SrcRegion?
     464         143 :     const CPLXMLNode *psSrcRegionNode = CPLGetXMLNode(psNode, "SrcRegion");
     465         143 :     if (psSrcRegionNode == nullptr && poProps == apoGeomFieldProps[0])
     466         131 :         psSrcRegionNode = CPLGetXMLNode(psNodeParent, "SrcRegion");
     467         143 :     const char *pszSrcRegion = CPLGetXMLValue(psSrcRegionNode, "", nullptr);
     468         143 :     if (pszSrcRegion != nullptr)
     469             :     {
     470          12 :         OGRGeometryFactory::createFromWkt(pszSrcRegion, nullptr,
     471             :                                           &poProps->poSrcRegion);
     472          12 :         if (poProps->poSrcRegion == nullptr)
     473             :         {
     474           1 :             CPLError(CE_Warning, CPLE_AppDefined,
     475             :                      "Ignoring SrcRegion. It must be a valid WKT geometry");
     476             :         }
     477             : 
     478          12 :         poProps->bSrcClip =
     479          12 :             CPLTestBool(CPLGetXMLValue(psSrcRegionNode, "clip", "FALSE"));
     480             :     }
     481             : 
     482             :     // Set Extent if provided.
     483         143 :     const char *pszExtentXMin = CPLGetXMLValue(psNode, "ExtentXMin", nullptr);
     484         143 :     const char *pszExtentYMin = CPLGetXMLValue(psNode, "ExtentYMin", nullptr);
     485         143 :     const char *pszExtentXMax = CPLGetXMLValue(psNode, "ExtentXMax", nullptr);
     486         143 :     const char *pszExtentYMax = CPLGetXMLValue(psNode, "ExtentYMax", nullptr);
     487         143 :     if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
     488           6 :         pszExtentXMax != nullptr && pszExtentYMax != nullptr)
     489             :     {
     490           6 :         poProps->sStaticEnvelope.MinX = CPLAtof(pszExtentXMin);
     491           6 :         poProps->sStaticEnvelope.MinY = CPLAtof(pszExtentYMin);
     492           6 :         poProps->sStaticEnvelope.MaxX = CPLAtof(pszExtentXMax);
     493           6 :         poProps->sStaticEnvelope.MaxY = CPLAtof(pszExtentYMax);
     494             :     }
     495             : 
     496         143 :     poProps->bNullable =
     497         143 :         CPLTestBool(CPLGetXMLValue(psNode, "nullable", "TRUE"));
     498             : 
     499         143 :     if (GetSrcLayerDefn()->GetGeomFieldCount() == 1)
     500             :     {
     501             :         poProps->sCoordinatePrecision =
     502          43 :             GetSrcLayerDefn()->GetGeomFieldDefn(0)->GetCoordinatePrecision();
     503             :     }
     504         100 :     else if (poProps->eGeometryStyle == VGS_Direct && poProps->iGeomField >= 0)
     505             :     {
     506             :         poProps->sCoordinatePrecision =
     507          12 :             GetSrcLayerDefn()
     508          12 :                 ->GetGeomFieldDefn(poProps->iGeomField)
     509          12 :                 ->GetCoordinatePrecision();
     510             :     }
     511         143 :     if (const char *pszXYResolution =
     512         143 :             CPLGetXMLValue(psNode, "XYResolution", nullptr))
     513             :     {
     514           1 :         poProps->sCoordinatePrecision.dfXYResolution = CPLAtof(pszXYResolution);
     515             :     }
     516         143 :     if (const char *pszZResolution =
     517         143 :             CPLGetXMLValue(psNode, "ZResolution", nullptr))
     518             :     {
     519           1 :         poProps->sCoordinatePrecision.dfZResolution = CPLAtof(pszZResolution);
     520             :     }
     521         143 :     if (const char *pszMResolution =
     522         143 :             CPLGetXMLValue(psNode, "MResolution", nullptr))
     523             :     {
     524           1 :         poProps->sCoordinatePrecision.dfMResolution = CPLAtof(pszMResolution);
     525             :     }
     526             : 
     527         143 :     return true;
     528             : }
     529             : 
     530             : /************************************************************************/
     531             : /*                         FullInitialize()                             */
     532             : /************************************************************************/
     533             : 
     534             : // TODO(schwehr): Remove gotos.
     535         499 : bool OGRVRTLayer::FullInitialize()
     536             : {
     537         499 :     if (bHasFullInitialized)
     538           0 :         return true;
     539             : 
     540         499 :     const char *pszSharedSetting = nullptr;
     541         499 :     const char *pszSQL = nullptr;
     542         499 :     const char *pszStyleFieldName = nullptr;
     543         499 :     CPLXMLNode *psChild = nullptr;
     544         499 :     bool bFoundGeometryField = false;
     545             : 
     546         499 :     bHasFullInitialized = true;
     547             : 
     548         499 :     poFeatureDefn = new OGRFeatureDefn(osName);
     549         499 :     poFeatureDefn->Reference();
     550             : 
     551         499 :     if (poDS->GetRecursionDetected())
     552          34 :         return false;
     553             : 
     554             :     // Figure out the data source name.  It may be treated relative
     555             :     // to vrt filename, but normally it is used directly.
     556         930 :     std::string osSrcDSName = CPLGetXMLValue(psLTree, "SrcDataSource", "");
     557             : 
     558         465 :     if (osSrcDSName.empty())
     559             :     {
     560          20 :         CPLError(CE_Failure, CPLE_AppDefined,
     561             :                  "Missing SrcDataSource for layer %s.", osName.c_str());
     562          20 :         goto error;
     563             :     }
     564             : 
     565         445 :     if (CPLTestBool(
     566         445 :             CPLGetXMLValue(psLTree, "SrcDataSource.relativetoVRT", "0")))
     567             :     {
     568             :         static const char *const apszPrefixes[] = {"CSV:", "GPSBABEL:"};
     569         258 :         bool bDone = false;
     570         774 :         for (size_t i = 0; i < sizeof(apszPrefixes) / sizeof(apszPrefixes[0]);
     571             :              i++)
     572             :         {
     573         516 :             const char *pszPrefix = apszPrefixes[i];
     574         516 :             if (EQUALN(osSrcDSName.c_str(), pszPrefix, strlen(pszPrefix)))
     575             :             {
     576           0 :                 auto nLastPart = osSrcDSName.find(':') + 1;
     577             :                 // CSV:z:/foo.xyz
     578           0 :                 if ((osSrcDSName[nLastPart] == '/' ||
     579           0 :                      osSrcDSName[nLastPart] == '\\') &&
     580           0 :                     nLastPart >= 3 && osSrcDSName[nLastPart - 3] == ':')
     581           0 :                     nLastPart -= 2;
     582           0 :                 CPLString osPrefix(osSrcDSName);
     583           0 :                 osPrefix.resize(nLastPart);
     584           0 :                 osSrcDSName = osPrefix + CPLProjectRelativeFilenameSafe(
     585             :                                              osVRTDirectory,
     586           0 :                                              osSrcDSName.c_str() + nLastPart);
     587           0 :                 bDone = true;
     588           0 :                 break;
     589             :             }
     590             :         }
     591         258 :         if (!bDone)
     592             :         {
     593         516 :             osSrcDSName = CPLProjectRelativeFilenameSafe(osVRTDirectory,
     594         258 :                                                          osSrcDSName.c_str());
     595             :         }
     596             :     }
     597             : 
     598             :     // Are we accessing this datasource in shared mode?  We default
     599             :     // to shared for SrcSQL requests, but we also allow the XML to
     600             :     // control our shared setting with an attribute on the
     601             :     // datasource element.
     602         445 :     pszSharedSetting = CPLGetXMLValue(psLTree, "SrcDataSource.shared", nullptr);
     603         445 :     if (pszSharedSetting == nullptr)
     604             :     {
     605         368 :         if (CPLGetXMLValue(psLTree, "SrcSQL", nullptr) == nullptr)
     606         365 :             pszSharedSetting = "OFF";
     607             :         else
     608           3 :             pszSharedSetting = "ON";
     609             :     }
     610             : 
     611         445 :     bSrcDSShared = CPLTestBool(pszSharedSetting);
     612             : 
     613             :     // Update mode doesn't make sense if we have a SrcSQL element.
     614         445 :     if (CPLGetXMLValue(psLTree, "SrcSQL", nullptr) != nullptr)
     615           3 :         bUpdate = false;
     616             : 
     617             :     // Try to access the datasource.
     618         445 : try_again:
     619         445 :     CPLErrorReset();
     620         445 :     if (EQUAL(osSrcDSName.c_str(), "@dummy@"))
     621             :     {
     622             :         GDALDriver *poMemDriver =
     623           0 :             OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
     624           0 :         if (poMemDriver != nullptr)
     625             :         {
     626           0 :             poSrcDS =
     627           0 :                 poMemDriver->Create("@dummy@", 0, 0, 0, GDT_Unknown, nullptr);
     628           0 :             poSrcDS->CreateLayer("@dummy@");
     629             :         }
     630             :     }
     631         445 :     else if (bSrcDSShared)
     632             :     {
     633          79 :         if (poDS->IsInForbiddenNames(osSrcDSName.c_str()))
     634             :         {
     635           4 :             CPLError(CE_Failure, CPLE_AppDefined,
     636             :                      "Cyclic VRT opening detected!");
     637           4 :             poDS->SetRecursionDetected();
     638             :         }
     639             :         else
     640             :         {
     641             :             char **papszOpenOptions =
     642          75 :                 GDALDeserializeOpenOptionsFromXML(psLTree);
     643          75 :             int l_nFlags = GDAL_OF_VECTOR | GDAL_OF_SHARED;
     644          75 :             if (bUpdate)
     645           0 :                 l_nFlags |= GDAL_OF_UPDATE;
     646          75 :             poSrcDS = (GDALDataset *)GDALOpenEx(
     647             :                 osSrcDSName.c_str(), l_nFlags, nullptr,
     648             :                 (const char *const *)papszOpenOptions, nullptr);
     649          75 :             CSLDestroy(papszOpenOptions);
     650             :             // Is it a VRT datasource?
     651          75 :             if (poSrcDS != nullptr && poSrcDS->GetDriver() == poDS->GetDriver())
     652             :             {
     653             :                 OGRVRTDataSource *poVRTSrcDS =
     654           3 :                     cpl::down_cast<OGRVRTDataSource *>(poSrcDS);
     655           3 :                 poVRTSrcDS->AddForbiddenNames(poDS->GetDescription());
     656             :             }
     657             :         }
     658             :     }
     659             :     else
     660             :     {
     661         366 :         if (poDS->GetCallLevel() < 32)
     662             :         {
     663             :             char **papszOpenOptions =
     664         364 :                 GDALDeserializeOpenOptionsFromXML(psLTree);
     665         364 :             int l_nFlags = GDAL_OF_VECTOR;
     666         364 :             if (bUpdate)
     667          42 :                 l_nFlags |= GDAL_OF_UPDATE;
     668         364 :             poSrcDS = (GDALDataset *)GDALOpenEx(
     669             :                 osSrcDSName.c_str(), l_nFlags, nullptr,
     670             :                 (const char *const *)papszOpenOptions, nullptr);
     671         364 :             CSLDestroy(papszOpenOptions);
     672             :             // Is it a VRT datasource?
     673         364 :             if (poSrcDS != nullptr && poSrcDS->GetDriver() == poDS->GetDriver())
     674             :             {
     675          66 :                 OGRVRTDataSource *poVRTSrcDS = (OGRVRTDataSource *)poSrcDS;
     676          66 :                 poVRTSrcDS->SetCallLevel(poDS->GetCallLevel() + 1);
     677          66 :                 poVRTSrcDS->SetParentDS(poDS);
     678             :             }
     679             :         }
     680             :         else
     681             :         {
     682           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     683             :                      "Trying to open a VRT from a VRT from a VRT from ... "
     684             :                      "[32 times] a VRT!");
     685             : 
     686           2 :             poDS->SetRecursionDetected();
     687             : 
     688           2 :             OGRVRTDataSource *poParent = poDS->GetParentDS();
     689          66 :             while (poParent != nullptr)
     690             :             {
     691          64 :                 poParent->SetRecursionDetected();
     692          64 :                 poParent = poParent->GetParentDS();
     693             :             }
     694             :         }
     695             :     }
     696             : 
     697         445 :     if (poSrcDS == nullptr)
     698             :     {
     699          10 :         if (bUpdate)
     700             :         {
     701           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     702             :                      "Cannot open datasource `%s' in update mode. "
     703             :                      "Trying again in read-only mode",
     704             :                      osSrcDSName.c_str());
     705           0 :             bUpdate = false;
     706           0 :             goto try_again;
     707             :         }
     708          10 :         if (strlen(CPLGetLastErrorMsg()) == 0)
     709           4 :             CPLError(CE_Failure, CPLE_AppDefined,
     710             :                      "Failed to open datasource `%s'.", osSrcDSName.c_str());
     711          10 :         goto error;
     712             :     }
     713             : 
     714             :     // Apply any metadata.
     715         435 :     oMDMD.XMLInit(psLTree, TRUE);
     716             : 
     717             :     // Is this layer derived from an SQL query result?
     718         435 :     pszSQL = CPLGetXMLValue(psLTree, "SrcSQL", nullptr);
     719             : 
     720         435 :     if (pszSQL != nullptr)
     721             :     {
     722             :         const char *pszDialect =
     723           3 :             CPLGetXMLValue(psLTree, "SrcSQL.dialect", nullptr);
     724           3 :         if (pszDialect != nullptr && pszDialect[0] == '\0')
     725           0 :             pszDialect = nullptr;
     726           3 :         poSrcLayer = poSrcDS->ExecuteSQL(pszSQL, nullptr, pszDialect);
     727           3 :         if (poSrcLayer == nullptr)
     728             :         {
     729           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     730             :                      "SQL statement failed, or returned no layer result:\n%s",
     731             :                      pszSQL);
     732           1 :             goto error;
     733             :         }
     734           2 :         bSrcLayerFromSQL = true;
     735             :     }
     736             : 
     737             :     // Fetch the layer if it is a regular layer.
     738         434 :     if (poSrcLayer == nullptr)
     739             :     {
     740             :         const char *pszSrcLayerName =
     741         432 :             CPLGetXMLValue(psLTree, "SrcLayer", osName);
     742             : 
     743         432 :         poSrcLayer = poSrcDS->GetLayerByName(pszSrcLayerName);
     744         432 :         if (poSrcLayer == nullptr)
     745             :         {
     746           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     747             :                      "Failed to find layer '%s' on datasource '%s'.",
     748             :                      pszSrcLayerName, osSrcDSName.c_str());
     749           2 :             goto error;
     750             :         }
     751             :     }
     752             : 
     753             :     // Search for GeometryField definitions.
     754             : 
     755             :     // Create as many OGRVRTGeomFieldProps as there are
     756             :     // GeometryField elements.
     757        1954 :     for (psChild = psLTree->psChild; psChild != nullptr;
     758        1522 :          psChild = psChild->psNext)
     759             :     {
     760        1526 :         if (psChild->eType == CXT_Element &&
     761        1043 :             EQUAL(psChild->pszValue, "GeometryField"))
     762             :         {
     763         137 :             if (!bFoundGeometryField)
     764             :             {
     765         131 :                 bFoundGeometryField = true;
     766             : 
     767             :                 // Recreate the first one if already taken into account in
     768             :                 // FastInitialize().
     769         131 :                 if (apoGeomFieldProps.size() == 1)
     770             :                 {
     771         111 :                     delete apoGeomFieldProps[0];
     772         111 :                     apoGeomFieldProps.resize(0);
     773             :                 }
     774             :             }
     775             : 
     776         137 :             apoGeomFieldProps.push_back(new OGRVRTGeomFieldProps());
     777         137 :             if (!ParseGeometryField(psChild, psLTree, apoGeomFieldProps.back()))
     778             :             {
     779           4 :                 goto error;
     780             :             }
     781             :         }
     782             :     }
     783             : 
     784         729 :     if (!bFoundGeometryField &&
     785         301 :         CPLGetXMLValue(psLTree, "SrcRegion", nullptr) != nullptr)
     786             :     {
     787           3 :         apoGeomFieldProps.push_back(new OGRVRTGeomFieldProps());
     788             :     }
     789             : 
     790         428 :     if (!bFoundGeometryField && apoGeomFieldProps.size() == 1)
     791             :     {
     792             :         // Otherwise use the top-level elements such as SrcRegion.
     793          10 :         if (!ParseGeometryField(nullptr, psLTree, apoGeomFieldProps[0]))
     794           0 :             goto error;
     795             :     }
     796             : 
     797         719 :     if (apoGeomFieldProps.empty() &&
     798         291 :         CPLGetXMLValue(psLTree, "GeometryType", nullptr) == nullptr)
     799             :     {
     800             :         // If no GeometryField is found but source geometry fields
     801             :         // exist, use them.
     802         286 :         for (int iGeomField = 0;
     803         587 :              iGeomField < GetSrcLayerDefn()->GetGeomFieldCount(); iGeomField++)
     804             :         {
     805         301 :             OGRVRTGeomFieldProps *poProps = new OGRVRTGeomFieldProps();
     806         301 :             apoGeomFieldProps.push_back(poProps);
     807             :             OGRGeomFieldDefn *poFDefn =
     808         301 :                 GetSrcLayerDefn()->GetGeomFieldDefn(iGeomField);
     809         301 :             poProps->osName = poFDefn->GetNameRef();
     810         301 :             poProps->eGeomType = poFDefn->GetType();
     811         301 :             if (poFDefn->GetSpatialRef() != nullptr)
     812         261 :                 poProps->poSRS = poFDefn->GetSpatialRef()->Clone();
     813         301 :             poProps->iGeomField = iGeomField;
     814         301 :             poProps->bNullable = CPL_TO_BOOL(poFDefn->IsNullable());
     815             :         }
     816             :     }
     817             : 
     818             :     // Instantiate real geometry fields from VRT properties.
     819         428 :     poFeatureDefn->SetGeomType(wkbNone);
     820         872 :     for (size_t i = 0; i < apoGeomFieldProps.size(); i++)
     821             :     {
     822         888 :         OGRGeomFieldDefn oFieldDefn(apoGeomFieldProps[i]->osName,
     823         888 :                                     apoGeomFieldProps[i]->eGeomType);
     824         444 :         oFieldDefn.SetSpatialRef(apoGeomFieldProps[i]->poSRS);
     825         444 :         oFieldDefn.SetNullable(apoGeomFieldProps[i]->bNullable);
     826         444 :         oFieldDefn.SetCoordinatePrecision(
     827         444 :             apoGeomFieldProps[i]->sCoordinatePrecision);
     828         444 :         poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
     829             :     }
     830             : 
     831         428 :     bAttrFilterPassThrough = true;
     832             : 
     833             :     // Figure out what should be used as an FID.
     834             :     {
     835         428 :         CPLXMLNode *psFIDNode = CPLGetXMLNode(psLTree, "FID");
     836         428 :         if (psFIDNode != nullptr)
     837             :         {
     838             :             const char *pszSrcFIDFieldName =
     839          31 :                 CPLGetXMLValue(psFIDNode, nullptr, "");
     840          31 :             if (!EQUAL(pszSrcFIDFieldName, ""))
     841             :             {
     842          31 :                 iFIDField = GetFieldIndexCaseSensitiveFirst(GetSrcLayerDefn(),
     843             :                                                             pszSrcFIDFieldName);
     844          31 :                 if (iFIDField == -1)
     845             :                 {
     846           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
     847             :                              "Unable to identify FID field '%s'.",
     848             :                              pszSrcFIDFieldName);
     849           1 :                     goto error;
     850             :                 }
     851             :             }
     852             : 
     853             :             // User facing FID column name.
     854             :             osFIDFieldName =
     855          30 :                 CPLGetXMLValue(psFIDNode, "name", pszSrcFIDFieldName);
     856          30 :             if (!EQUAL(osFIDFieldName, poSrcLayer->GetFIDColumn()))
     857             :             {
     858          30 :                 bAttrFilterPassThrough = false;
     859             :             }
     860             :         }
     861             :         else
     862             :         {
     863         397 :             osFIDFieldName = poSrcLayer->GetFIDColumn();
     864             :         }
     865             :     }
     866             : 
     867             :     // Figure out what should be used as a Style.
     868         427 :     pszStyleFieldName = CPLGetXMLValue(psLTree, "Style", nullptr);
     869             : 
     870         427 :     if (pszStyleFieldName != nullptr)
     871             :     {
     872           5 :         iStyleField = GetFieldIndexCaseSensitiveFirst(GetSrcLayerDefn(),
     873             :                                                       pszStyleFieldName);
     874           5 :         if (iStyleField == -1)
     875             :         {
     876           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     877             :                      "Unable to identify Style field '%s'.", pszStyleFieldName);
     878           1 :             goto error;
     879             :         }
     880             : 
     881           4 :         if (!EQUAL(pszStyleFieldName, "OGR_STYLE"))
     882             :         {
     883           4 :             bAttrFilterPassThrough = false;
     884             :         }
     885             :     }
     886             : 
     887             :     // Search for schema definitions in the VRT.
     888        1927 :     for (psChild = psLTree->psChild; psChild != nullptr;
     889        1501 :          psChild = psChild->psNext)
     890             :     {
     891        1508 :         if (psChild->eType == CXT_Element && EQUAL(psChild->pszValue, "Field"))
     892             :         {
     893             :             // Field name.
     894          88 :             const char *pszName = CPLGetXMLValue(psChild, "name", nullptr);
     895          88 :             if (pszName == nullptr)
     896             :             {
     897           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     898             :                          "Unable to identify Field name.");
     899           7 :                 goto error;
     900             :             }
     901             : 
     902          87 :             OGRFieldDefn oFieldDefn(pszName, OFTString);
     903             : 
     904             :             // Type.
     905          87 :             const char *pszArg = CPLGetXMLValue(psChild, "type", nullptr);
     906             : 
     907          87 :             if (pszArg != nullptr)
     908             :             {
     909          73 :                 int iType = 0;  // Used after for.
     910             : 
     911         351 :                 for (; iType <= static_cast<int>(OFTMaxType); iType++)
     912             :                 {
     913         350 :                     if (EQUAL(pszArg, OGRFieldDefn::GetFieldTypeName(
     914             :                                           static_cast<OGRFieldType>(iType))))
     915             :                     {
     916          72 :                         oFieldDefn.SetType(static_cast<OGRFieldType>(iType));
     917          72 :                         break;
     918             :                     }
     919             :                 }
     920             : 
     921          73 :                 if (iType > static_cast<int>(OFTMaxType))
     922             :                 {
     923           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
     924             :                              "Unable to identify Field type '%s'.", pszArg);
     925           1 :                     goto error;
     926             :                 }
     927             :             }
     928             : 
     929             :             // Subtype.
     930          86 :             pszArg = CPLGetXMLValue(psChild, "subtype", nullptr);
     931          86 :             if (pszArg != nullptr)
     932             :             {
     933           7 :                 OGRFieldSubType eSubType = OFSTNone;
     934             : 
     935           7 :                 int iType = 0;  // Used after for.
     936          19 :                 for (; iType <= static_cast<int>(OFSTMaxSubType); iType++)
     937             :                 {
     938          18 :                     if (EQUAL(pszArg, OGRFieldDefn::GetFieldSubTypeName(
     939             :                                           static_cast<OGRFieldSubType>(iType))))
     940             :                     {
     941           6 :                         eSubType = static_cast<OGRFieldSubType>(iType);
     942           6 :                         break;
     943             :                     }
     944             :                 }
     945             : 
     946           7 :                 if (iType > static_cast<int>(OFSTMaxSubType))
     947             :                 {
     948           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
     949             :                              "Unable to identify Field subtype '%s'.", pszArg);
     950           1 :                     goto error;
     951             :                 }
     952             : 
     953           6 :                 if (!OGR_AreTypeSubTypeCompatible(oFieldDefn.GetType(),
     954             :                                                   eSubType))
     955             :                 {
     956           1 :                     CPLError(
     957             :                         CE_Failure, CPLE_AppDefined,
     958             :                         "Invalid subtype '%s' for type '%s'.", pszArg,
     959             :                         OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
     960           1 :                     goto error;
     961             :                 }
     962             : 
     963           5 :                 oFieldDefn.SetSubType(eSubType);
     964             :             }
     965             : 
     966             :             // Width and precision.
     967          84 :             int nWidth = atoi(CPLGetXMLValue(psChild, "width", "0"));
     968          84 :             if (nWidth < 0)
     969             :             {
     970           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
     971             :                          "Invalid width for field %s.", pszName);
     972           1 :                 goto error;
     973             :             }
     974          83 :             oFieldDefn.SetWidth(nWidth);
     975             : 
     976          83 :             int nPrecision = atoi(CPLGetXMLValue(psChild, "precision", "0"));
     977          83 :             if (nPrecision < 0 || nPrecision > 1024)
     978             :             {
     979           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
     980             :                          "Invalid precision for field %s.", pszName);
     981           1 :                 goto error;
     982             :             }
     983          82 :             oFieldDefn.SetPrecision(nPrecision);
     984             : 
     985             :             // Nullable attribute.
     986             :             const bool bNullable =
     987          82 :                 CPLTestBool(CPLGetXMLValue(psChild, "nullable", "true"));
     988          82 :             oFieldDefn.SetNullable(bNullable);
     989             : 
     990             :             // Unique attribute.
     991             :             const bool bUnique =
     992          82 :                 CPLTestBool(CPLGetXMLValue(psChild, "unique", "false"));
     993          82 :             oFieldDefn.SetUnique(bUnique);
     994             : 
     995             :             // Default attribute.
     996          82 :             oFieldDefn.SetDefault(CPLGetXMLValue(psChild, "default", nullptr));
     997             : 
     998             :             const char *pszAlternativeName =
     999          82 :                 CPLGetXMLValue(psChild, "alternativeName", nullptr);
    1000          82 :             if (pszAlternativeName)
    1001           1 :                 oFieldDefn.SetAlternativeName(pszAlternativeName);
    1002             : 
    1003             :             const char *pszComment =
    1004          82 :                 CPLGetXMLValue(psChild, "comment", nullptr);
    1005          82 :             if (pszComment)
    1006           1 :                 oFieldDefn.SetComment(pszComment);
    1007             : 
    1008             :             // Create the field.
    1009          82 :             poFeatureDefn->AddFieldDefn(&oFieldDefn);
    1010             : 
    1011          82 :             abDirectCopy.push_back(FALSE);
    1012             : 
    1013             :             // Source field.
    1014             :             int iSrcField =
    1015          82 :                 GetFieldIndexCaseSensitiveFirst(GetSrcLayerDefn(), pszName);
    1016             : 
    1017          82 :             pszArg = CPLGetXMLValue(psChild, "src", nullptr);
    1018             : 
    1019          82 :             if (pszArg != nullptr)
    1020             :             {
    1021          59 :                 iSrcField =
    1022          59 :                     GetFieldIndexCaseSensitiveFirst(GetSrcLayerDefn(), pszArg);
    1023          59 :                 if (iSrcField == -1)
    1024             :                 {
    1025           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1026             :                              "Unable to find source field '%s'.", pszArg);
    1027           1 :                     goto error;
    1028             :                 }
    1029             :             }
    1030             : 
    1031          81 :             if (iSrcField < 0 ||
    1032          58 :                 (pszArg != nullptr && strcmp(pszArg, pszName) != 0))
    1033             :             {
    1034           7 :                 bAttrFilterPassThrough = false;
    1035             :             }
    1036             :             else
    1037             :             {
    1038             :                 OGRFieldDefn *poSrcFieldDefn =
    1039          74 :                     GetSrcLayerDefn()->GetFieldDefn(iSrcField);
    1040          74 :                 if (poSrcFieldDefn->GetType() != oFieldDefn.GetType())
    1041          48 :                     bAttrFilterPassThrough = false;
    1042             :             }
    1043             : 
    1044          81 :             anSrcField.push_back(iSrcField);
    1045             :         }
    1046             :     }
    1047             : 
    1048         419 :     CPLAssert(poFeatureDefn->GetFieldCount() ==
    1049             :               static_cast<int>(anSrcField.size()));
    1050             : 
    1051             :     // Create the schema, if it was not explicitly in the VRT.
    1052         419 :     if (poFeatureDefn->GetFieldCount() == 0)
    1053             :     {
    1054         389 :         const int nSrcFieldCount = GetSrcLayerDefn()->GetFieldCount();
    1055             : 
    1056        1337 :         for (int iSrcField = 0; iSrcField < nSrcFieldCount; iSrcField++)
    1057             :         {
    1058         948 :             bool bSkip = false;
    1059        2164 :             for (size_t iGF = 0; iGF < apoGeomFieldProps.size(); iGF++)
    1060             :             {
    1061        1244 :                 if (!apoGeomFieldProps[iGF]->bReportSrcColumn &&
    1062          20 :                     (iSrcField == apoGeomFieldProps[iGF]->iGeomXField ||
    1063          16 :                      iSrcField == apoGeomFieldProps[iGF]->iGeomYField ||
    1064          12 :                      iSrcField == apoGeomFieldProps[iGF]->iGeomZField ||
    1065          12 :                      iSrcField == apoGeomFieldProps[iGF]->iGeomMField ||
    1066          12 :                      (apoGeomFieldProps[iGF]->eGeometryStyle != VGS_Direct &&
    1067          12 :                       iSrcField == apoGeomFieldProps[iGF]->iGeomField)))
    1068             :                 {
    1069           8 :                     bSkip = true;
    1070           8 :                     break;
    1071             :                 }
    1072             :             }
    1073         948 :             if (bSkip)
    1074           8 :                 continue;
    1075             : 
    1076        2820 :             poFeatureDefn->AddFieldDefn(
    1077         940 :                 GetSrcLayerDefn()->GetFieldDefn(iSrcField));
    1078         940 :             anSrcField.push_back(iSrcField);
    1079         940 :             abDirectCopy.push_back(TRUE);
    1080             :         }
    1081             : 
    1082         389 :         bAttrFilterPassThrough = true;
    1083             :     }
    1084             : 
    1085             :     // Is VRT layer definition identical to the source layer defn?
    1086             :     // If so, use it directly, and save the translation of features.
    1087         804 :     if (GetSrcLayerDefn() != nullptr && iFIDField == -1 && iStyleField == -1 &&
    1088         385 :         GetSrcLayerDefn()->IsSame(poFeatureDefn))
    1089             :     {
    1090         231 :         bool bSame = true;
    1091         517 :         for (size_t i = 0; i < apoGeomFieldProps.size(); i++)
    1092             :         {
    1093         572 :             if (apoGeomFieldProps[i]->eGeometryStyle != VGS_Direct ||
    1094         286 :                 apoGeomFieldProps[i]->iGeomField != static_cast<int>(i))
    1095             :             {
    1096           0 :                 bSame = false;
    1097           0 :                 break;
    1098             :             }
    1099             :         }
    1100         231 :         if (bSame)
    1101             :         {
    1102         231 :             CPLDebug("VRT", "Source feature definition is identical to VRT "
    1103             :                             "feature definition. Use optimized path");
    1104         231 :             poFeatureDefn->Release();
    1105         231 :             poFeatureDefn = GetSrcLayerDefn();
    1106         231 :             poFeatureDefn->Reference();
    1107         517 :             for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
    1108             :             {
    1109         286 :                 if (apoGeomFieldProps[i]->poSRS != nullptr)
    1110             :                     const_cast<OGRSpatialReference *>(
    1111         250 :                         apoGeomFieldProps[i]->poSRS)
    1112         250 :                         ->Release();
    1113         572 :                 apoGeomFieldProps[i]->poSRS =
    1114         286 :                     poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef();
    1115         286 :                 if (apoGeomFieldProps[i]->poSRS != nullptr)
    1116             :                     const_cast<OGRSpatialReference *>(
    1117         250 :                         apoGeomFieldProps[i]->poSRS)
    1118         250 :                         ->Reference();
    1119             :             }
    1120             :         }
    1121             :     }
    1122             : 
    1123         419 :     CPLAssert(poFeatureDefn->GetGeomFieldCount() ==
    1124             :               static_cast<int>(apoGeomFieldProps.size()));
    1125             : 
    1126             :     // Allow vrt to override whether attribute filters should be
    1127             :     // passed through.
    1128         419 :     if (CPLGetXMLValue(psLTree, "attrFilterPassThrough", nullptr) != nullptr)
    1129           0 :         bAttrFilterPassThrough = CPLTestBool(
    1130           0 :             CPLGetXMLValue(psLTree, "attrFilterPassThrough", "TRUE"));
    1131             : 
    1132         419 :     SetIgnoredFields(nullptr);
    1133             : 
    1134         419 :     return true;
    1135             : 
    1136          46 : error:
    1137          46 :     bError = true;
    1138          46 :     poFeatureDefn->Release();
    1139          46 :     poFeatureDefn = new OGRFeatureDefn(osName);
    1140          46 :     poFeatureDefn->SetGeomType(wkbNone);
    1141          46 :     poFeatureDefn->Reference();
    1142          77 :     for (size_t i = 0; i < apoGeomFieldProps.size(); i++)
    1143          31 :         delete apoGeomFieldProps[i];
    1144          46 :     apoGeomFieldProps.clear();
    1145          46 :     return false;
    1146             : }
    1147             : 
    1148             : /************************************************************************/
    1149             : /*                            ResetReading()                            */
    1150             : /************************************************************************/
    1151             : 
    1152        4891 : void OGRVRTLayer::ResetReading()
    1153             : {
    1154        4891 :     bNeedReset = true;
    1155        4891 : }
    1156             : 
    1157             : /************************************************************************/
    1158             : /*                         ResetSourceReading()                         */
    1159             : /************************************************************************/
    1160             : 
    1161        1427 : bool OGRVRTLayer::ResetSourceReading()
    1162             : 
    1163             : {
    1164        1427 :     bool bSuccess = true;
    1165             : 
    1166             :     // Do we want to let source layer do spatial restriction?
    1167        1427 :     char *pszFilter = nullptr;
    1168        4304 :     for (size_t i = 0; i < apoGeomFieldProps.size(); i++)
    1169             :     {
    1170        2063 :         if ((m_poFilterGeom || apoGeomFieldProps[i]->poSrcRegion) &&
    1171        5004 :             apoGeomFieldProps[i]->bUseSpatialSubquery &&
    1172          32 :             apoGeomFieldProps[i]->eGeometryStyle == VGS_PointFromColumns)
    1173             :         {
    1174          64 :             OGRFieldDefn *poXField = poSrcLayer->GetLayerDefn()->GetFieldDefn(
    1175          32 :                 apoGeomFieldProps[i]->iGeomXField);
    1176          64 :             OGRFieldDefn *poYField = poSrcLayer->GetLayerDefn()->GetFieldDefn(
    1177          32 :                 apoGeomFieldProps[i]->iGeomYField);
    1178             : 
    1179          32 :             const char *pszXField = poXField->GetNameRef();
    1180          32 :             const char *pszYField = poYField->GetNameRef();
    1181             : 
    1182          32 :             OGRFieldType xType = poXField->GetType();
    1183          32 :             OGRFieldType yType = poYField->GetType();
    1184          32 :             if (!((xType == OFTReal || xType == OFTInteger ||
    1185             :                    xType == OFTInteger64) &&
    1186           0 :                   (yType == OFTReal || yType == OFTInteger ||
    1187             :                    yType == OFTInteger64)))
    1188             :             {
    1189           2 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1190             :                          "The '%s' and/or '%s' fields of the source layer "
    1191             :                          "are not declared as numeric fields, "
    1192             :                          "so the spatial filter cannot be turned into an "
    1193             :                          "attribute filter on them",
    1194             :                          pszXField, pszYField);
    1195           2 :                 apoGeomFieldProps[i]->bUseSpatialSubquery = false;
    1196             :             }
    1197             : 
    1198          32 :             if (apoGeomFieldProps[i]->bUseSpatialSubquery)
    1199             :             {
    1200          30 :                 OGREnvelope sEnvelope;
    1201          60 :                 CPLString osFilter;
    1202             : 
    1203          30 :                 if (apoGeomFieldProps[i]->poSrcRegion != nullptr)
    1204             :                 {
    1205           5 :                     if (m_poFilterGeom == nullptr)
    1206             :                     {
    1207           3 :                         apoGeomFieldProps[i]->poSrcRegion->getEnvelope(
    1208           3 :                             &sEnvelope);
    1209             :                     }
    1210             :                     else
    1211             :                     {
    1212             :                         auto poIntersection = std::unique_ptr<OGRGeometry>(
    1213           2 :                             apoGeomFieldProps[i]->poSrcRegion->Intersection(
    1214           4 :                                 m_poFilterGeom));
    1215           2 :                         if (poIntersection && !poIntersection->IsEmpty())
    1216             :                         {
    1217           2 :                             poIntersection->getEnvelope(&sEnvelope);
    1218             :                         }
    1219             :                         else
    1220             :                         {
    1221           0 :                             sEnvelope.MinX = 0;
    1222           0 :                             sEnvelope.MaxX = 0;
    1223           0 :                             sEnvelope.MinY = 0;
    1224           0 :                             sEnvelope.MaxY = 0;
    1225             :                         }
    1226             :                     }
    1227             :                 }
    1228             :                 else
    1229             :                 {
    1230          25 :                     m_poFilterGeom->getEnvelope(&sEnvelope);
    1231             :                 }
    1232             : 
    1233          30 :                 if (!std::isinf(sEnvelope.MinX))
    1234             :                     osFilter +=
    1235          28 :                         CPLSPrintf("\"%s\" > %.15g", pszXField, sEnvelope.MinX);
    1236           2 :                 else if (sEnvelope.MinX > 0)
    1237           0 :                     osFilter += "0 = 1";
    1238             : 
    1239          30 :                 if (!std::isinf(sEnvelope.MaxX))
    1240             :                 {
    1241          28 :                     if (!osFilter.empty())
    1242          28 :                         osFilter += " AND ";
    1243             :                     osFilter +=
    1244          28 :                         CPLSPrintf("\"%s\" < %.15g", pszXField, sEnvelope.MaxX);
    1245             :                 }
    1246           2 :                 else if (sEnvelope.MaxX < 0)
    1247             :                 {
    1248           0 :                     if (!osFilter.empty())
    1249           0 :                         osFilter += " AND ";
    1250           0 :                     osFilter += "0 = 1";
    1251             :                 }
    1252             : 
    1253          30 :                 if (!std::isinf(sEnvelope.MinY))
    1254             :                 {
    1255          28 :                     if (!osFilter.empty())
    1256          28 :                         osFilter += " AND ";
    1257             :                     osFilter +=
    1258          28 :                         CPLSPrintf("\"%s\" > %.15g", pszYField, sEnvelope.MinY);
    1259             :                 }
    1260           2 :                 else if (sEnvelope.MinY > 0)
    1261             :                 {
    1262           0 :                     if (!osFilter.empty())
    1263           0 :                         osFilter += " AND ";
    1264           0 :                     osFilter += "0 = 1";
    1265             :                 }
    1266             : 
    1267          30 :                 if (!std::isinf(sEnvelope.MaxY))
    1268             :                 {
    1269          28 :                     if (!osFilter.empty())
    1270          28 :                         osFilter += " AND ";
    1271             :                     osFilter +=
    1272          28 :                         CPLSPrintf("\"%s\" < %.15g", pszYField, sEnvelope.MaxY);
    1273             :                 }
    1274           2 :                 else if (sEnvelope.MaxY < 0)
    1275             :                 {
    1276           0 :                     if (!osFilter.empty())
    1277           0 :                         osFilter += " AND ";
    1278           0 :                     osFilter += "0 = 1";
    1279             :                 }
    1280             : 
    1281          30 :                 if (!osFilter.empty())
    1282             :                 {
    1283          28 :                     pszFilter = CPLStrdup(osFilter);
    1284             :                 }
    1285             :             }
    1286             : 
    1287             :             // Just do it on one geometry field. To complicated otherwise!
    1288          32 :             break;
    1289             :         }
    1290             :     }
    1291             : 
    1292             :     // Install spatial + attr filter query on source layer.
    1293        1427 :     if (pszFilter == nullptr && pszAttrFilter == nullptr)
    1294             :     {
    1295        1127 :         bSuccess = poSrcLayer->SetAttributeFilter(nullptr) == OGRERR_NONE;
    1296             :     }
    1297         300 :     else if (pszFilter != nullptr && pszAttrFilter == nullptr)
    1298             :     {
    1299          21 :         bSuccess = poSrcLayer->SetAttributeFilter(pszFilter) == OGRERR_NONE;
    1300             :     }
    1301         279 :     else if (pszFilter == nullptr && pszAttrFilter != nullptr)
    1302             :     {
    1303         272 :         bSuccess = poSrcLayer->SetAttributeFilter(pszAttrFilter) == OGRERR_NONE;
    1304             :     }
    1305             :     else
    1306             :     {
    1307           7 :         CPLString osMerged = pszFilter;
    1308             : 
    1309           7 :         osMerged += " AND (";
    1310           7 :         osMerged += pszAttrFilter;
    1311           7 :         osMerged += ")";
    1312             : 
    1313           7 :         bSuccess = poSrcLayer->SetAttributeFilter(osMerged) == OGRERR_NONE;
    1314             :     }
    1315             : 
    1316        1427 :     CPLFree(pszFilter);
    1317             : 
    1318        1427 :     m_bEmptyResultSet = false;
    1319             : 
    1320             :     // Clear spatial filter (to be safe) for non direct geometries
    1321             :     // and reset reading.
    1322        1427 :     if (m_iGeomFieldFilter < static_cast<int>(apoGeomFieldProps.size()) &&
    1323        2691 :         apoGeomFieldProps[m_iGeomFieldFilter]->eGeometryStyle == VGS_Direct &&
    1324        1264 :         apoGeomFieldProps[m_iGeomFieldFilter]->iGeomField >= 0)
    1325             :     {
    1326        1264 :         OGRGeometry *poNewSpatialGeom = nullptr;
    1327             :         OGRGeometry *poSrcRegion =
    1328        1264 :             apoGeomFieldProps[m_iGeomFieldFilter]->poSrcRegion;
    1329        1264 :         std::unique_ptr<OGRGeometry> poIntersection;
    1330             : 
    1331        1264 :         if (poSrcRegion == nullptr)
    1332             :         {
    1333        1207 :             poNewSpatialGeom = m_poFilterGeom;
    1334             :         }
    1335          57 :         else if (m_poFilterGeom == nullptr)
    1336             :         {
    1337          40 :             poNewSpatialGeom = poSrcRegion;
    1338             :         }
    1339             :         else
    1340             :         {
    1341          17 :             bool bDoIntersection = true;
    1342          17 :             if (m_bFilterIsEnvelope)
    1343             :             {
    1344          13 :                 OGREnvelope sEnvelope;
    1345          13 :                 m_poFilterGeom->getEnvelope(&sEnvelope);
    1346          15 :                 if (std::isinf(sEnvelope.MinX) && std::isinf(sEnvelope.MinY) &&
    1347           2 :                     std::isinf(sEnvelope.MaxX) && std::isinf(sEnvelope.MaxY) &&
    1348           1 :                     sEnvelope.MinX < 0 && sEnvelope.MinY < 0 &&
    1349          14 :                     sEnvelope.MaxX > 0 && sEnvelope.MaxY > 0)
    1350             :                 {
    1351           1 :                     poNewSpatialGeom = poSrcRegion;
    1352           1 :                     bDoIntersection = false;
    1353             :                 }
    1354             :             }
    1355          17 :             if (bDoIntersection)
    1356             :             {
    1357          16 :                 poIntersection.reset(m_poFilterGeom->Intersection(poSrcRegion));
    1358          16 :                 poNewSpatialGeom = poIntersection.get();
    1359          16 :                 if (!poIntersection)
    1360           0 :                     m_bEmptyResultSet = true;
    1361             :             }
    1362             :         }
    1363        1264 :         poSrcLayer->SetSpatialFilter(
    1364        1264 :             apoGeomFieldProps[m_iGeomFieldFilter]->iGeomField,
    1365        1264 :             poNewSpatialGeom);
    1366             :     }
    1367             :     else
    1368             :     {
    1369         163 :         poSrcLayer->SetSpatialFilter(nullptr);
    1370             :     }
    1371        1427 :     poSrcLayer->ResetReading();
    1372        1427 :     bNeedReset = false;
    1373             : 
    1374        1427 :     return bSuccess;
    1375             : }
    1376             : 
    1377             : /************************************************************************/
    1378             : /*                           GetNextFeature()                           */
    1379             : /************************************************************************/
    1380             : 
    1381       25382 : OGRFeature *OGRVRTLayer::GetNextFeature()
    1382             : 
    1383             : {
    1384       25382 :     if (m_bEmptyResultSet)
    1385           0 :         return nullptr;
    1386       25382 :     if (!bHasFullInitialized)
    1387          41 :         FullInitialize();
    1388       25382 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    1389           7 :         return nullptr;
    1390       25375 :     if (bError)
    1391          13 :         return nullptr;
    1392             : 
    1393       25362 :     if (bNeedReset)
    1394             :     {
    1395        1309 :         if (!ResetSourceReading())
    1396           2 :             return nullptr;
    1397             :     }
    1398             : 
    1399             :     for (; true;)
    1400             :     {
    1401       25368 :         OGRFeature *poSrcFeature = poSrcLayer->GetNextFeature();
    1402       25368 :         if (poSrcFeature == nullptr)
    1403       25360 :             return nullptr;
    1404             : 
    1405       24310 :         OGRFeature *poFeature = nullptr;
    1406       24310 :         if (poFeatureDefn == GetSrcLayerDefn())
    1407             :         {
    1408        3408 :             poFeature = poSrcFeature;
    1409        3408 :             ClipAndAssignSRS(poFeature);
    1410             :         }
    1411             :         else
    1412             :         {
    1413       20902 :             poFeature = TranslateFeature(poSrcFeature, TRUE);
    1414       20902 :             delete poSrcFeature;
    1415             :         }
    1416             : 
    1417       24310 :         if (poFeature == nullptr)
    1418           4 :             return nullptr;
    1419             : 
    1420       24306 :         if (((m_iGeomFieldFilter < static_cast<int>(apoGeomFieldProps.size()) &&
    1421       24271 :               apoGeomFieldProps[m_iGeomFieldFilter]->eGeometryStyle ==
    1422       20514 :                   VGS_Direct) ||
    1423       20514 :              m_poFilterGeom == nullptr ||
    1424       49025 :              FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
    1425       24302 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
    1426       24298 :             return poFeature;
    1427             : 
    1428           8 :         delete poFeature;
    1429           8 :     }
    1430             : }
    1431             : 
    1432             : /************************************************************************/
    1433             : /*                          ClipAndAssignSRS()                          */
    1434             : /************************************************************************/
    1435             : 
    1436       24339 : void OGRVRTLayer::ClipAndAssignSRS(OGRFeature *poFeature)
    1437             : {
    1438       49797 :     for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
    1439             :     {
    1440             :         // Clip the geometry to the SrcRegion if asked.
    1441       25458 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
    1442       25458 :         if (apoGeomFieldProps[i]->poSrcRegion != nullptr &&
    1443       25458 :             apoGeomFieldProps[i]->bSrcClip && poGeom != nullptr)
    1444             :         {
    1445          37 :             poGeom = poGeom->Intersection(apoGeomFieldProps[i]->poSrcRegion);
    1446          37 :             if (poGeom != nullptr)
    1447          37 :                 poGeom->assignSpatialReference(
    1448          37 :                     GetLayerDefn()->GetGeomFieldDefn(i)->GetSpatialRef());
    1449             : 
    1450          37 :             poFeature->SetGeomFieldDirectly(i, poGeom);
    1451             :         }
    1452       25421 :         else if (poGeom != nullptr)
    1453       24640 :             poGeom->assignSpatialReference(
    1454       24640 :                 GetLayerDefn()->GetGeomFieldDefn(i)->GetSpatialRef());
    1455             :     }
    1456       24339 : }
    1457             : 
    1458             : /************************************************************************/
    1459             : /*                          TranslateFeature()                          */
    1460             : /*                                                                      */
    1461             : /*      Translate a source feature into a feature for this layer.       */
    1462             : /************************************************************************/
    1463             : 
    1464       20931 : OGRFeature *OGRVRTLayer::TranslateFeature(OGRFeature *&poSrcFeat,
    1465             :                                           int bUseSrcRegion)
    1466             : 
    1467             : {
    1468       20931 : retry:
    1469       20931 :     OGRFeature *poDstFeat = new OGRFeature(poFeatureDefn);
    1470             : 
    1471       20931 :     m_nFeaturesRead++;
    1472             : 
    1473             :     // Handle FID.
    1474       20931 :     if (iFIDField == -1)
    1475       20903 :         poDstFeat->SetFID(poSrcFeat->GetFID());
    1476             :     else
    1477          28 :         poDstFeat->SetFID(poSrcFeat->GetFieldAsInteger64(iFIDField));
    1478             : 
    1479             :     // Handle style string.
    1480       20931 :     if (iStyleField != -1)
    1481             :     {
    1482          12 :         if (poSrcFeat->IsFieldSetAndNotNull(iStyleField))
    1483          12 :             poDstFeat->SetStyleString(poSrcFeat->GetFieldAsString(iStyleField));
    1484             :     }
    1485             :     else
    1486             :     {
    1487       20919 :         if (poSrcFeat->GetStyleString() != nullptr)
    1488           0 :             poDstFeat->SetStyleString(poSrcFeat->GetStyleString());
    1489             :     }
    1490             : 
    1491       41911 :     for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
    1492             :     {
    1493             :         OGRVRTGeometryStyle eGeometryStyle =
    1494       20994 :             apoGeomFieldProps[i]->eGeometryStyle;
    1495       20994 :         int iGeomField = apoGeomFieldProps[i]->iGeomField;
    1496             : 
    1497             :         // Handle the geometry.  Eventually there will be several more
    1498             :         // supported options.
    1499       41988 :         if (eGeometryStyle == VGS_None ||
    1500       20994 :             GetLayerDefn()->GetGeomFieldDefn(i)->IsIgnored())
    1501             :         {
    1502             :             // Do nothing.
    1503             :         }
    1504       20966 :         else if (eGeometryStyle == VGS_WKT && iGeomField != -1)
    1505             :         {
    1506          63 :             const char *pszWKT = poSrcFeat->GetFieldAsString(iGeomField);
    1507             : 
    1508          63 :             if (pszWKT != nullptr)
    1509             :             {
    1510          63 :                 OGRGeometry *poGeom = nullptr;
    1511             : 
    1512          63 :                 OGRGeometryFactory::createFromWkt(pszWKT, nullptr, &poGeom);
    1513          63 :                 if (poGeom == nullptr)
    1514           0 :                     CPLDebug("OGR_VRT", "Did not get geometry from %s", pszWKT);
    1515             : 
    1516          63 :                 poDstFeat->SetGeomFieldDirectly(i, poGeom);
    1517          63 :             }
    1518             :         }
    1519       20903 :         else if (eGeometryStyle == VGS_WKB && iGeomField != -1)
    1520             :         {
    1521           1 :             int nBytes = 0;
    1522           1 :             GByte *pabyWKB = nullptr;
    1523           1 :             bool bNeedFree = false;
    1524             : 
    1525           1 :             if (poSrcFeat->GetFieldDefnRef(iGeomField)->GetType() == OFTBinary)
    1526             :             {
    1527           0 :                 pabyWKB = poSrcFeat->GetFieldAsBinary(iGeomField, &nBytes);
    1528             :             }
    1529             :             else
    1530             :             {
    1531           1 :                 const char *pszWKT = poSrcFeat->GetFieldAsString(iGeomField);
    1532             : 
    1533           1 :                 pabyWKB = CPLHexToBinary(pszWKT, &nBytes);
    1534           1 :                 bNeedFree = true;
    1535             :             }
    1536             : 
    1537           1 :             if (pabyWKB != nullptr)
    1538             :             {
    1539           1 :                 OGRGeometry *poGeom = nullptr;
    1540             : 
    1541           1 :                 if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
    1542           1 :                                                       nBytes) == OGRERR_NONE)
    1543           1 :                     poDstFeat->SetGeomFieldDirectly(i, poGeom);
    1544             :             }
    1545             : 
    1546           1 :             if (bNeedFree)
    1547           1 :                 CPLFree(pabyWKB);
    1548             :         }
    1549       20902 :         else if (eGeometryStyle == VGS_Shape && iGeomField != -1)
    1550             :         {
    1551           3 :             int nBytes = 0;
    1552           3 :             GByte *pabyWKB = nullptr;
    1553           3 :             bool bNeedFree = false;
    1554             : 
    1555           3 :             if (poSrcFeat->GetFieldDefnRef(iGeomField)->GetType() == OFTBinary)
    1556             :             {
    1557           0 :                 pabyWKB = poSrcFeat->GetFieldAsBinary(iGeomField, &nBytes);
    1558             :             }
    1559             :             else
    1560             :             {
    1561           3 :                 const char *pszWKT = poSrcFeat->GetFieldAsString(iGeomField);
    1562             : 
    1563           3 :                 pabyWKB = CPLHexToBinary(pszWKT, &nBytes);
    1564           3 :                 bNeedFree = true;
    1565             :             }
    1566             : 
    1567           3 :             if (pabyWKB != nullptr)
    1568             :             {
    1569           3 :                 OGRGeometry *poGeom = nullptr;
    1570             : 
    1571           3 :                 if (OGRCreateFromShapeBin(pabyWKB, &poGeom, nBytes) ==
    1572             :                     OGRERR_NONE)
    1573           3 :                     poDstFeat->SetGeomFieldDirectly(i, poGeom);
    1574             :             }
    1575             : 
    1576           3 :             if (bNeedFree)
    1577           3 :                 CPLFree(pabyWKB);
    1578             :         }
    1579       20899 :         else if (eGeometryStyle == VGS_Direct && iGeomField != -1)
    1580             :         {
    1581         426 :             poDstFeat->SetGeomField(i, poSrcFeat->GetGeomFieldRef(iGeomField));
    1582             :         }
    1583       20473 :         else if (eGeometryStyle == VGS_PointFromColumns)
    1584             :         {
    1585       20473 :             OGRPoint *poPoint = nullptr;
    1586       20473 :             if (apoGeomFieldProps[i]->iGeomZField != -1)
    1587             :             {
    1588       40822 :                 poPoint = new OGRPoint(poSrcFeat->GetFieldAsDouble(
    1589       20411 :                                            apoGeomFieldProps[i]->iGeomXField),
    1590       20411 :                                        poSrcFeat->GetFieldAsDouble(
    1591       20411 :                                            apoGeomFieldProps[i]->iGeomYField),
    1592       20411 :                                        poSrcFeat->GetFieldAsDouble(
    1593       40822 :                                            apoGeomFieldProps[i]->iGeomZField));
    1594             :             }
    1595             :             else
    1596             :             {
    1597         124 :                 poPoint = new OGRPoint(poSrcFeat->GetFieldAsDouble(
    1598          62 :                                            apoGeomFieldProps[i]->iGeomXField),
    1599          62 :                                        poSrcFeat->GetFieldAsDouble(
    1600         124 :                                            apoGeomFieldProps[i]->iGeomYField));
    1601             :             }
    1602       20473 :             if (apoGeomFieldProps[i]->iGeomMField >= 0)
    1603             :             {
    1604           1 :                 poPoint->setM(poSrcFeat->GetFieldAsDouble(
    1605           1 :                     apoGeomFieldProps[i]->iGeomMField));
    1606             :             }
    1607       20473 :             poDstFeat->SetGeomFieldDirectly(i, poPoint);
    1608             :         }
    1609             :         else
    1610             :         {
    1611             :             // Add other options here.
    1612             :         }
    1613             : 
    1614             :         // In the non-direct case, we need to check that the geometry
    1615             :         // intersects the source region before an optional clipping.
    1616       41964 :         if (bUseSrcRegion &&
    1617       41527 :             apoGeomFieldProps[i]->eGeometryStyle != VGS_Direct &&
    1618       20533 :             apoGeomFieldProps[i]->poSrcRegion != nullptr)
    1619             :         {
    1620          24 :             OGRGeometry *poGeom = poDstFeat->GetGeomFieldRef(i);
    1621          48 :             if (poGeom != nullptr &&
    1622          24 :                 !poGeom->Intersects(apoGeomFieldProps[i]->poSrcRegion))
    1623             :             {
    1624          14 :                 delete poSrcFeat;
    1625          14 :                 delete poDstFeat;
    1626             : 
    1627             :                 // Fetch next source feature and retry translating it.
    1628          14 :                 poSrcFeat = poSrcLayer->GetNextFeature();
    1629          14 :                 if (poSrcFeat == nullptr)
    1630           4 :                     return nullptr;
    1631             : 
    1632          10 :                 goto retry;
    1633             :             }
    1634             :         }
    1635             :     }
    1636             : 
    1637       20917 :     ClipAndAssignSRS(poDstFeat);
    1638             : 
    1639             :     // Copy fields.
    1640       83939 :     for (int iVRTField = 0; iVRTField < poFeatureDefn->GetFieldCount();
    1641             :          iVRTField++)
    1642             :     {
    1643       63022 :         if (anSrcField[iVRTField] == -1)
    1644           8 :             continue;
    1645             : 
    1646       63014 :         OGRFieldDefn *poDstDefn = poFeatureDefn->GetFieldDefn(iVRTField);
    1647             :         OGRFieldDefn *poSrcDefn =
    1648       63014 :             poSrcLayer->GetLayerDefn()->GetFieldDefn(anSrcField[iVRTField]);
    1649             : 
    1650      125992 :         if (!poSrcFeat->IsFieldSetAndNotNull(anSrcField[iVRTField]) ||
    1651       62978 :             poDstDefn->IsIgnored())
    1652          38 :             continue;
    1653             : 
    1654      125952 :         if (abDirectCopy[iVRTField] &&
    1655       62976 :             poDstDefn->GetType() == poSrcDefn->GetType())
    1656             :         {
    1657       62877 :             poDstFeat->SetField(
    1658       62877 :                 iVRTField, poSrcFeat->GetRawFieldRef(anSrcField[iVRTField]));
    1659             :         }
    1660             :         else
    1661             :         {
    1662             :             // Eventually we need to offer some more sophisticated translation
    1663             :             // options here for more esoteric types.
    1664          99 :             if (poDstDefn->GetType() == OFTReal)
    1665          16 :                 poDstFeat->SetField(iVRTField, poSrcFeat->GetFieldAsDouble(
    1666          16 :                                                    anSrcField[iVRTField]));
    1667             :             else
    1668          83 :                 poDstFeat->SetField(iVRTField, poSrcFeat->GetFieldAsString(
    1669          83 :                                                    anSrcField[iVRTField]));
    1670             :         }
    1671             :     }
    1672             : 
    1673       20917 :     return poDstFeat;
    1674             : }
    1675             : 
    1676             : /************************************************************************/
    1677             : /*                             GetFeature()                             */
    1678             : /************************************************************************/
    1679             : 
    1680          58 : OGRFeature *OGRVRTLayer::GetFeature(GIntBig nFeatureId)
    1681             : 
    1682             : {
    1683          58 :     if (!bHasFullInitialized)
    1684           3 :         FullInitialize();
    1685          58 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    1686           1 :         return nullptr;
    1687             : 
    1688          57 :     bNeedReset = true;
    1689             : 
    1690             :     // If the FID is directly mapped, we can do a simple
    1691             :     // GetFeature() to get our target feature.  Otherwise we need
    1692             :     // to setup an appropriate query to get it.
    1693          57 :     OGRFeature *poSrcFeature = nullptr;
    1694          57 :     OGRFeature *poFeature = nullptr;
    1695             : 
    1696          57 :     if (iFIDField == -1)
    1697             :     {
    1698          55 :         poSrcFeature = poSrcLayer->GetFeature(nFeatureId);
    1699             :     }
    1700             :     else
    1701             :     {
    1702             :         const char *pszFID =
    1703           2 :             poSrcLayer->GetLayerDefn()->GetFieldDefn(iFIDField)->GetNameRef();
    1704           2 :         char *pszFIDQuery = static_cast<char *>(CPLMalloc(strlen(pszFID) + 64));
    1705             : 
    1706           2 :         poSrcLayer->ResetReading();
    1707           2 :         snprintf(pszFIDQuery, strlen(pszFID) + 64, "%s = " CPL_FRMT_GIB, pszFID,
    1708             :                  nFeatureId);
    1709           2 :         poSrcLayer->SetSpatialFilter(nullptr);
    1710           2 :         poSrcLayer->SetAttributeFilter(pszFIDQuery);
    1711           2 :         CPLFree(pszFIDQuery);
    1712             : 
    1713           2 :         poSrcFeature = poSrcLayer->GetNextFeature();
    1714             :     }
    1715             : 
    1716          57 :     if (poSrcFeature == nullptr)
    1717          24 :         return nullptr;
    1718             : 
    1719             :     // Translate feature and return it.
    1720          33 :     if (poFeatureDefn == GetSrcLayerDefn())
    1721             :     {
    1722          14 :         poFeature = poSrcFeature;
    1723          14 :         ClipAndAssignSRS(poFeature);
    1724             :     }
    1725             :     else
    1726             :     {
    1727          19 :         poFeature = TranslateFeature(poSrcFeature, FALSE);
    1728          19 :         delete poSrcFeature;
    1729             :     }
    1730             : 
    1731          33 :     return poFeature;
    1732             : }
    1733             : 
    1734             : /************************************************************************/
    1735             : /*                          SetNextByIndex()                            */
    1736             : /************************************************************************/
    1737             : 
    1738          24 : OGRErr OGRVRTLayer::SetNextByIndex(GIntBig nIndex)
    1739             : {
    1740          24 :     if (!bHasFullInitialized)
    1741           2 :         FullInitialize();
    1742          24 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    1743           1 :         return OGRERR_FAILURE;
    1744             : 
    1745          23 :     if (bNeedReset)
    1746             :     {
    1747           1 :         if (!ResetSourceReading())
    1748           0 :             return OGRERR_FAILURE;
    1749             :     }
    1750             : 
    1751          23 :     if (TestCapability(OLCFastSetNextByIndex))
    1752          13 :         return poSrcLayer->SetNextByIndex(nIndex);
    1753             : 
    1754          10 :     return OGRLayer::SetNextByIndex(nIndex);
    1755             : }
    1756             : 
    1757             : /************************************************************************/
    1758             : /*               TranslateVRTFeatureToSrcFeature()                      */
    1759             : /*                                                                      */
    1760             : /*      Translate a VRT feature into a feature for the source layer     */
    1761             : /************************************************************************/
    1762             : 
    1763             : OGRFeature *
    1764           5 : OGRVRTLayer::TranslateVRTFeatureToSrcFeature(OGRFeature *poVRTFeature)
    1765             : {
    1766           5 :     OGRFeature *poSrcFeat = new OGRFeature(poSrcLayer->GetLayerDefn());
    1767             : 
    1768           5 :     poSrcFeat->SetFID(poVRTFeature->GetFID());
    1769             : 
    1770             :     // Handle style string.
    1771           5 :     if (iStyleField != -1)
    1772             :     {
    1773           1 :         if (poVRTFeature->GetStyleString() != nullptr)
    1774           0 :             poSrcFeat->SetField(iStyleField, poVRTFeature->GetStyleString());
    1775             :     }
    1776             :     else
    1777             :     {
    1778           4 :         if (poVRTFeature->GetStyleString() != nullptr)
    1779           0 :             poSrcFeat->SetStyleString(poVRTFeature->GetStyleString());
    1780             :     }
    1781             : 
    1782             :     // Handle the geometry.  Eventually there will be several more
    1783             :     // supported options.
    1784          10 :     for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
    1785             :     {
    1786             :         OGRVRTGeometryStyle eGeometryStyle =
    1787           5 :             apoGeomFieldProps[i]->eGeometryStyle;
    1788           5 :         int iGeomField = apoGeomFieldProps[i]->iGeomField;
    1789             : 
    1790           5 :         if (eGeometryStyle == VGS_None)
    1791             :         {
    1792             :             // Do nothing.
    1793             :         }
    1794           5 :         else if (eGeometryStyle == VGS_WKT && iGeomField >= 0)
    1795             :         {
    1796           1 :             OGRGeometry *poGeom = poVRTFeature->GetGeomFieldRef(i);
    1797           1 :             if (poGeom != nullptr)
    1798             :             {
    1799           1 :                 char *pszWKT = nullptr;
    1800           1 :                 if (poGeom->exportToWkt(&pszWKT) == OGRERR_NONE)
    1801             :                 {
    1802           1 :                     poSrcFeat->SetField(iGeomField, pszWKT);
    1803             :                 }
    1804           1 :                 CPLFree(pszWKT);
    1805           1 :             }
    1806             :         }
    1807           4 :         else if (eGeometryStyle == VGS_WKB && iGeomField >= 0)
    1808             :         {
    1809           1 :             OGRGeometry *poGeom = poVRTFeature->GetGeomFieldRef(i);
    1810           1 :             if (poGeom != nullptr)
    1811             :             {
    1812           1 :                 const size_t nSize = poGeom->WkbSize();
    1813           1 :                 if (nSize >
    1814           1 :                     static_cast<size_t>(std::numeric_limits<int>::max()))
    1815             :                 {
    1816             :                 }
    1817             :                 else
    1818             :                 {
    1819             :                     GByte *pabyData =
    1820           1 :                         static_cast<GByte *>(VSI_MALLOC_VERBOSE(nSize));
    1821           2 :                     if (pabyData &&
    1822           1 :                         poGeom->exportToWkb(wkbNDR, pabyData) == OGRERR_NONE)
    1823             :                     {
    1824           1 :                         if (poSrcFeat->GetFieldDefnRef(iGeomField)->GetType() ==
    1825             :                             OFTBinary)
    1826             :                         {
    1827           0 :                             poSrcFeat->SetField(
    1828             :                                 iGeomField, static_cast<int>(nSize), pabyData);
    1829             :                         }
    1830             :                         else
    1831             :                         {
    1832           1 :                             char *pszHexWKB = CPLBinaryToHex(
    1833             :                                 static_cast<int>(nSize), pabyData);
    1834           1 :                             poSrcFeat->SetField(iGeomField, pszHexWKB);
    1835           1 :                             CPLFree(pszHexWKB);
    1836             :                         }
    1837             :                     }
    1838           1 :                     CPLFree(pabyData);
    1839             :                 }
    1840           1 :             }
    1841             :         }
    1842           3 :         else if (eGeometryStyle == VGS_Shape)
    1843             :         {
    1844           0 :             CPLDebug("OGR_VRT", "Update of VGS_Shape geometries not supported");
    1845             :         }
    1846           3 :         else if (eGeometryStyle == VGS_Direct && iGeomField >= 0)
    1847             :         {
    1848           2 :             poSrcFeat->SetGeomField(iGeomField,
    1849           2 :                                     poVRTFeature->GetGeomFieldRef(i));
    1850             :         }
    1851           1 :         else if (eGeometryStyle == VGS_PointFromColumns)
    1852             :         {
    1853           1 :             OGRGeometry *poGeom = poVRTFeature->GetGeomFieldRef(i);
    1854           1 :             if (poGeom != nullptr)
    1855             :             {
    1856           1 :                 if (wkbFlatten(poGeom->getGeometryType()) != wkbPoint)
    1857             :                 {
    1858           0 :                     CPLError(CE_Warning, CPLE_NotSupported,
    1859             :                              "Cannot set a non ponctual geometry for "
    1860             :                              "PointFromColumns geometry");
    1861             :                 }
    1862             :                 else
    1863             :                 {
    1864           1 :                     auto poPoint = poGeom->toPoint();
    1865           1 :                     poSrcFeat->SetField(apoGeomFieldProps[i]->iGeomXField,
    1866             :                                         poPoint->getX());
    1867           1 :                     poSrcFeat->SetField(apoGeomFieldProps[i]->iGeomYField,
    1868             :                                         poPoint->getY());
    1869           1 :                     if (apoGeomFieldProps[i]->iGeomZField != -1)
    1870             :                     {
    1871           0 :                         poSrcFeat->SetField(apoGeomFieldProps[i]->iGeomZField,
    1872             :                                             poPoint->getZ());
    1873             :                     }
    1874           1 :                     if (apoGeomFieldProps[i]->iGeomMField != -1)
    1875             :                     {
    1876           0 :                         poSrcFeat->SetField(apoGeomFieldProps[i]->iGeomMField,
    1877             :                                             poPoint->getM());
    1878             :                     }
    1879             :                 }
    1880             :             }
    1881             :         }
    1882             :         else
    1883             :         {
    1884             :             // Add other options here.
    1885             :         }
    1886             : 
    1887           5 :         OGRGeometry *poGeom = poSrcFeat->GetGeomFieldRef(i);
    1888           5 :         if (poGeom != nullptr)
    1889           2 :             poGeom->assignSpatialReference(
    1890           2 :                 GetLayerDefn()->GetGeomFieldDefn(i)->GetSpatialRef());
    1891             :     }
    1892             : 
    1893             :     // Copy fields.
    1894          16 :     for (int iVRTField = 0; iVRTField < poFeatureDefn->GetFieldCount();
    1895             :          iVRTField++)
    1896             :     {
    1897          11 :         bool bSkip = false;
    1898          20 :         for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
    1899             :         {
    1900             :             // Do not set source geometry columns. Have been set just above.
    1901          11 :             if ((apoGeomFieldProps[i]->eGeometryStyle != VGS_Direct &&
    1902           9 :                  anSrcField[iVRTField] == apoGeomFieldProps[i]->iGeomField) ||
    1903           9 :                 anSrcField[iVRTField] == apoGeomFieldProps[i]->iGeomXField ||
    1904           9 :                 anSrcField[iVRTField] == apoGeomFieldProps[i]->iGeomYField ||
    1905          31 :                 anSrcField[iVRTField] == apoGeomFieldProps[i]->iGeomZField ||
    1906           9 :                 anSrcField[iVRTField] == apoGeomFieldProps[i]->iGeomMField)
    1907             :             {
    1908           2 :                 bSkip = true;
    1909           2 :                 break;
    1910             :             }
    1911             :         }
    1912          11 :         if (bSkip)
    1913           2 :             continue;
    1914             : 
    1915           9 :         OGRFieldDefn *poVRTDefn = poFeatureDefn->GetFieldDefn(iVRTField);
    1916             :         OGRFieldDefn *poSrcDefn =
    1917           9 :             poSrcLayer->GetLayerDefn()->GetFieldDefn(anSrcField[iVRTField]);
    1918             : 
    1919          18 :         if (abDirectCopy[iVRTField] &&
    1920           9 :             poVRTDefn->GetType() == poSrcDefn->GetType())
    1921             :         {
    1922           9 :             poSrcFeat->SetField(anSrcField[iVRTField],
    1923           9 :                                 poVRTFeature->GetRawFieldRef(iVRTField));
    1924             :         }
    1925             :         else
    1926             :         {
    1927             :             // Eventually we need to offer some more sophisticated translation
    1928             :             // options here for more esoteric types.
    1929           0 :             poSrcFeat->SetField(anSrcField[iVRTField],
    1930             :                                 poVRTFeature->GetFieldAsString(iVRTField));
    1931             :         }
    1932             :     }
    1933             : 
    1934           5 :     return poSrcFeat;
    1935             : }
    1936             : 
    1937             : /************************************************************************/
    1938             : /*                           ICreateFeature()                            */
    1939             : /************************************************************************/
    1940             : 
    1941          11 : OGRErr OGRVRTLayer::ICreateFeature(OGRFeature *poVRTFeature)
    1942             : {
    1943          11 :     if (!bHasFullInitialized)
    1944           0 :         FullInitialize();
    1945          11 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    1946           1 :         return OGRERR_FAILURE;
    1947             : 
    1948          10 :     if (!bUpdate)
    1949             :     {
    1950           2 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    1951             :                  "CreateFeature");
    1952           2 :         return OGRERR_FAILURE;
    1953             :     }
    1954             : 
    1955           8 :     if (iFIDField != -1)
    1956             :     {
    1957           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1958             :                  "The CreateFeature() operation is not supported "
    1959             :                  "if the FID option is specified.");
    1960           0 :         return OGRERR_FAILURE;
    1961             :     }
    1962             : 
    1963           8 :     if (GetSrcLayerDefn() == poFeatureDefn)
    1964           5 :         return poSrcLayer->CreateFeature(poVRTFeature);
    1965             : 
    1966           3 :     OGRFeature *poSrcFeature = TranslateVRTFeatureToSrcFeature(poVRTFeature);
    1967           3 :     poSrcFeature->SetFID(OGRNullFID);
    1968           3 :     OGRErr eErr = poSrcLayer->CreateFeature(poSrcFeature);
    1969           3 :     if (eErr == OGRERR_NONE)
    1970             :     {
    1971           3 :         poVRTFeature->SetFID(poSrcFeature->GetFID());
    1972             :     }
    1973           3 :     delete poSrcFeature;
    1974           3 :     return eErr;
    1975             : }
    1976             : 
    1977             : /************************************************************************/
    1978             : /*                             ISetFeature()                             */
    1979             : /************************************************************************/
    1980             : 
    1981          16 : OGRErr OGRVRTLayer::ISetFeature(OGRFeature *poVRTFeature)
    1982             : {
    1983          16 :     if (!bHasFullInitialized)
    1984           0 :         FullInitialize();
    1985          16 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    1986           1 :         return OGRERR_FAILURE;
    1987             : 
    1988          15 :     if (!bUpdate)
    1989             :     {
    1990          10 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    1991             :                  "SetFeature");
    1992          10 :         return OGRERR_FAILURE;
    1993             :     }
    1994             : 
    1995           5 :     if (iFIDField != -1)
    1996             :     {
    1997           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1998             :                  "The SetFeature() operation is not supported "
    1999             :                  "if the FID option is specified.");
    2000           0 :         return OGRERR_FAILURE;
    2001             :     }
    2002             : 
    2003           5 :     if (GetSrcLayerDefn() == poFeatureDefn)
    2004           3 :         return poSrcLayer->SetFeature(poVRTFeature);
    2005             : 
    2006           2 :     OGRFeature *poSrcFeature = TranslateVRTFeatureToSrcFeature(poVRTFeature);
    2007           2 :     OGRErr eErr = poSrcLayer->SetFeature(poSrcFeature);
    2008           2 :     delete poSrcFeature;
    2009           2 :     return eErr;
    2010             : }
    2011             : 
    2012             : /************************************************************************/
    2013             : /*                           DeleteFeature()                            */
    2014             : /************************************************************************/
    2015             : 
    2016          20 : OGRErr OGRVRTLayer::DeleteFeature(GIntBig nFID)
    2017             : 
    2018             : {
    2019          20 :     if (!bHasFullInitialized)
    2020           2 :         FullInitialize();
    2021          20 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2022           1 :         return OGRERR_FAILURE;
    2023             : 
    2024          19 :     if (!bUpdate)
    2025             :     {
    2026          18 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    2027             :                  "DeleteFeature");
    2028          18 :         return OGRERR_FAILURE;
    2029             :     }
    2030             : 
    2031           1 :     if (iFIDField != -1)
    2032             :     {
    2033           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2034             :                  "The DeleteFeature() operation is not supported "
    2035             :                  "if the FID option is specified.");
    2036           0 :         return OGRERR_FAILURE;
    2037             :     }
    2038             : 
    2039           1 :     return poSrcLayer->DeleteFeature(nFID);
    2040             : }
    2041             : 
    2042             : /************************************************************************/
    2043             : /*                         SetAttributeFilter()                         */
    2044             : /************************************************************************/
    2045             : 
    2046        1892 : OGRErr OGRVRTLayer::SetAttributeFilter(const char *pszNewQuery)
    2047             : 
    2048             : {
    2049        1892 :     if (!bHasFullInitialized)
    2050          94 :         FullInitialize();
    2051        1892 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2052          43 :         return OGRERR_FAILURE;
    2053             : 
    2054        1849 :     if (bAttrFilterPassThrough)
    2055             :     {
    2056        1841 :         CPLFree(pszAttrFilter);
    2057        1841 :         if (pszNewQuery == nullptr || strlen(pszNewQuery) == 0)
    2058        1345 :             pszAttrFilter = nullptr;
    2059             :         else
    2060         496 :             pszAttrFilter = CPLStrdup(pszNewQuery);
    2061             : 
    2062        1841 :         ResetReading();
    2063        1841 :         return OGRERR_NONE;
    2064             :     }
    2065             :     else
    2066             :     {
    2067             :         // Setup m_poAttrQuery.
    2068           8 :         return OGRLayer::SetAttributeFilter(pszNewQuery);
    2069             :     }
    2070             : }
    2071             : 
    2072             : /************************************************************************/
    2073             : /*                           TestCapability()                           */
    2074             : /************************************************************************/
    2075             : 
    2076        1957 : int OGRVRTLayer::TestCapability(const char *pszCap)
    2077             : 
    2078             : {
    2079        1957 :     if (EQUAL(pszCap, OLCFastFeatureCount) && nFeatureCount >= 0 &&
    2080           0 :         m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
    2081           0 :         return TRUE;
    2082             : 
    2083        1977 :     if (EQUAL(pszCap, OLCFastGetExtent) && apoGeomFieldProps.size() == 1 &&
    2084          20 :         apoGeomFieldProps[0]->sStaticEnvelope.IsInit())
    2085           3 :         return TRUE;
    2086             : 
    2087        1954 :     if (!bHasFullInitialized)
    2088          28 :         FullInitialize();
    2089        1954 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2090          11 :         return FALSE;
    2091             : 
    2092        1943 :     if (EQUAL(pszCap, OLCFastFeatureCount) ||
    2093        1542 :         EQUAL(pszCap, OLCFastSetNextByIndex))
    2094             :     {
    2095         424 :         if (m_poAttrQuery == nullptr)
    2096             :         {
    2097         424 :             bool bForward = true;
    2098        1265 :             for (size_t i = 0; i < apoGeomFieldProps.size(); i++)
    2099             :             {
    2100         902 :                 if (!(apoGeomFieldProps[i]->eGeometryStyle == VGS_Direct ||
    2101          39 :                       (apoGeomFieldProps[i]->poSrcRegion == nullptr &&
    2102          31 :                        m_poFilterGeom == nullptr)))
    2103             :                 {
    2104          22 :                     bForward = false;
    2105          22 :                     break;
    2106             :                 }
    2107             :             }
    2108         424 :             if (bForward)
    2109             :             {
    2110         402 :                 return poSrcLayer->TestCapability(pszCap);
    2111             :             }
    2112             :         }
    2113          22 :         return FALSE;
    2114             :     }
    2115             : 
    2116        1519 :     else if (EQUAL(pszCap, OLCFastSpatialFilter))
    2117           9 :         return apoGeomFieldProps.size() == 1 &&
    2118           8 :                apoGeomFieldProps[0]->eGeometryStyle == VGS_Direct &&
    2119          17 :                m_poAttrQuery == nullptr && poSrcLayer->TestCapability(pszCap);
    2120             : 
    2121        1510 :     else if (EQUAL(pszCap, OLCFastGetExtent))
    2122          42 :         return apoGeomFieldProps.size() == 1 &&
    2123          19 :                apoGeomFieldProps[0]->eGeometryStyle == VGS_Direct &&
    2124          19 :                m_poAttrQuery == nullptr &&
    2125          19 :                (apoGeomFieldProps[0]->poSrcRegion == nullptr ||
    2126          61 :                 apoGeomFieldProps[0]->bSrcClip) &&
    2127          61 :                poSrcLayer->TestCapability(pszCap);
    2128             : 
    2129        1468 :     else if (EQUAL(pszCap, OLCRandomRead))
    2130           1 :         return iFIDField == -1 && poSrcLayer->TestCapability(pszCap);
    2131             : 
    2132        1467 :     else if (EQUAL(pszCap, OLCSequentialWrite) ||
    2133        1457 :              EQUAL(pszCap, OLCRandomWrite) || EQUAL(pszCap, OLCDeleteFeature))
    2134          28 :         return bUpdate && iFIDField == -1 && poSrcLayer->TestCapability(pszCap);
    2135             : 
    2136        1439 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
    2137         141 :         return poSrcLayer->TestCapability(pszCap);
    2138             : 
    2139        1298 :     else if (EQUAL(pszCap, OLCTransactions))
    2140           1 :         return bUpdate && poSrcLayer->TestCapability(pszCap);
    2141             : 
    2142        1297 :     else if (EQUAL(pszCap, OLCIgnoreFields) ||
    2143         178 :              EQUAL(pszCap, OLCCurveGeometries) ||
    2144         130 :              EQUAL(pszCap, OLCZGeometries) ||
    2145         106 :              EQUAL(pszCap, OLCMeasuredGeometries))
    2146        1239 :         return poSrcLayer->TestCapability(pszCap);
    2147             : 
    2148          58 :     return FALSE;
    2149             : }
    2150             : 
    2151             : /************************************************************************/
    2152             : /*                              GetExtent()                             */
    2153             : /************************************************************************/
    2154             : 
    2155          12 : OGRErr OGRVRTLayer::GetExtent(OGREnvelope *psExtent, int bForce)
    2156             : {
    2157          12 :     return GetExtent(0, psExtent, bForce);
    2158             : }
    2159             : 
    2160         105 : OGRErr OGRVRTLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
    2161             : {
    2162         105 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount())
    2163          18 :         return OGRERR_FAILURE;
    2164             : 
    2165          87 :     if (static_cast<size_t>(iGeomField) >= apoGeomFieldProps.size())
    2166           0 :         return OGRERR_FAILURE;
    2167             : 
    2168          87 :     if (apoGeomFieldProps[iGeomField]->sStaticEnvelope.IsInit())
    2169             :     {
    2170           5 :         *psExtent = apoGeomFieldProps[iGeomField]->sStaticEnvelope;
    2171           5 :         return OGRERR_NONE;
    2172             :     }
    2173             : 
    2174          82 :     if (!bHasFullInitialized)
    2175           0 :         FullInitialize();
    2176          82 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2177           0 :         return OGRERR_FAILURE;
    2178             : 
    2179          82 :     if (apoGeomFieldProps[iGeomField]->eGeometryStyle == VGS_Direct &&
    2180         161 :         m_poAttrQuery == nullptr &&
    2181          79 :         (apoGeomFieldProps[iGeomField]->poSrcRegion == nullptr ||
    2182           1 :          apoGeomFieldProps[iGeomField]->bSrcClip))
    2183             :     {
    2184          78 :         if (bNeedReset)
    2185          42 :             ResetSourceReading();
    2186             : 
    2187          78 :         OGRErr eErr = poSrcLayer->GetExtent(
    2188          78 :             apoGeomFieldProps[iGeomField]->iGeomField, psExtent, bForce);
    2189         153 :         if (eErr != OGRERR_NONE ||
    2190          75 :             apoGeomFieldProps[iGeomField]->poSrcRegion == nullptr)
    2191          78 :             return eErr;
    2192             : 
    2193           0 :         OGREnvelope sSrcRegionEnvelope;
    2194           0 :         apoGeomFieldProps[iGeomField]->poSrcRegion->getEnvelope(
    2195           0 :             &sSrcRegionEnvelope);
    2196             : 
    2197           0 :         psExtent->Intersect(sSrcRegionEnvelope);
    2198           0 :         return eErr;
    2199             :     }
    2200             : 
    2201           4 :     return OGRLayer::GetExtentInternal(iGeomField, psExtent, bForce);
    2202             : }
    2203             : 
    2204             : /************************************************************************/
    2205             : /*                          GetFeatureCount()                           */
    2206             : /************************************************************************/
    2207             : 
    2208         399 : GIntBig OGRVRTLayer::GetFeatureCount(int bForce)
    2209             : 
    2210             : {
    2211         399 :     if (m_bEmptyResultSet)
    2212           0 :         return 0;
    2213         399 :     if (nFeatureCount >= 0 && m_poFilterGeom == nullptr &&
    2214           2 :         m_poAttrQuery == nullptr)
    2215             :     {
    2216           2 :         return nFeatureCount;
    2217             :     }
    2218             : 
    2219         397 :     if (!bHasFullInitialized)
    2220           5 :         FullInitialize();
    2221         397 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2222           6 :         return 0;
    2223             : 
    2224         391 :     if (TestCapability(OLCFastFeatureCount))
    2225             :     {
    2226          81 :         if (bNeedReset)
    2227          75 :             ResetSourceReading();
    2228             : 
    2229          81 :         return poSrcLayer->GetFeatureCount(bForce);
    2230             :     }
    2231             : 
    2232         310 :     return OGRLayer::GetFeatureCount(bForce);
    2233             : }
    2234             : 
    2235             : /************************************************************************/
    2236             : /*                          SetSpatialFilter()                          */
    2237             : /************************************************************************/
    2238             : 
    2239         308 : void OGRVRTLayer::SetSpatialFilter(OGRGeometry *poGeomIn)
    2240             : {
    2241         308 :     SetSpatialFilter(0, poGeomIn);
    2242         308 : }
    2243             : 
    2244        1899 : void OGRVRTLayer::SetSpatialFilter(int iGeomField, OGRGeometry *poGeomIn)
    2245             : {
    2246        1899 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount())
    2247             :     {
    2248          59 :         if (poGeomIn != nullptr)
    2249             :         {
    2250          12 :             CPLError(CE_Failure, CPLE_AppDefined,
    2251             :                      "Invalid geometry field index : %d", iGeomField);
    2252             :         }
    2253          59 :         return;
    2254             :     }
    2255             : 
    2256        1840 :     if (!bHasFullInitialized)
    2257           0 :         FullInitialize();
    2258        1840 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2259           5 :         return;
    2260             : 
    2261        1835 :     if (apoGeomFieldProps[iGeomField]->eGeometryStyle == VGS_Direct)
    2262        1811 :         bNeedReset = true;
    2263             : 
    2264        1835 :     m_iGeomFieldFilter = iGeomField;
    2265        1835 :     if (InstallFilter(poGeomIn))
    2266         686 :         ResetReading();
    2267             : }
    2268             : 
    2269             : /************************************************************************/
    2270             : /*                             SyncToDisk()                             */
    2271             : /************************************************************************/
    2272             : 
    2273           3 : OGRErr OGRVRTLayer::SyncToDisk()
    2274             : {
    2275           3 :     if (!bHasFullInitialized)
    2276           2 :         FullInitialize();
    2277           3 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2278           1 :         return OGRERR_FAILURE;
    2279             : 
    2280           2 :     return poSrcLayer->SyncToDisk();
    2281             : }
    2282             : 
    2283             : /************************************************************************/
    2284             : /*                            GetLayerDefn()                            */
    2285             : /************************************************************************/
    2286             : 
    2287       79752 : OGRFeatureDefn *OGRVRTLayer::GetLayerDefn()
    2288             : {
    2289       79752 :     if (!bHasFullInitialized)
    2290         312 :         FullInitialize();
    2291             : 
    2292       79752 :     return poFeatureDefn;
    2293             : }
    2294             : 
    2295             : /************************************************************************/
    2296             : /*                             GetGeomType()                            */
    2297             : /************************************************************************/
    2298             : 
    2299          75 : OGRwkbGeometryType OGRVRTLayer::GetGeomType()
    2300             : {
    2301          90 :     if (CPLGetXMLValue(psLTree, "GeometryType", nullptr) != nullptr ||
    2302          15 :         CPLGetXMLValue(psLTree, "GeometryField.GeometryType", nullptr) !=
    2303             :             nullptr)
    2304             :     {
    2305          62 :         if (apoGeomFieldProps.size() >= 1)
    2306          60 :             return apoGeomFieldProps[0]->eGeomType;
    2307           2 :         return wkbNone;
    2308             :     }
    2309             : 
    2310          13 :     return GetLayerDefn()->GetGeomType();
    2311             : }
    2312             : 
    2313             : /************************************************************************/
    2314             : /*                             GetFIDColumn()                           */
    2315             : /************************************************************************/
    2316             : 
    2317         215 : const char *OGRVRTLayer::GetFIDColumn()
    2318             : {
    2319         215 :     if (!bHasFullInitialized)
    2320           6 :         FullInitialize();
    2321         215 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2322          35 :         return "";
    2323             : 
    2324         180 :     return osFIDFieldName;
    2325             : }
    2326             : 
    2327             : /************************************************************************/
    2328             : /*                           StartTransaction()                         */
    2329             : /************************************************************************/
    2330             : 
    2331           3 : OGRErr OGRVRTLayer::StartTransaction()
    2332             : {
    2333           3 :     if (!bHasFullInitialized)
    2334           1 :         FullInitialize();
    2335           3 :     if (!poSrcLayer || !bUpdate || poDS->GetRecursionDetected())
    2336           1 :         return OGRERR_FAILURE;
    2337             : 
    2338           2 :     return poSrcLayer->StartTransaction();
    2339             : }
    2340             : 
    2341             : /************************************************************************/
    2342             : /*                           CommitTransaction()                        */
    2343             : /************************************************************************/
    2344             : 
    2345           2 : OGRErr OGRVRTLayer::CommitTransaction()
    2346             : {
    2347           2 :     if (!bHasFullInitialized)
    2348           1 :         FullInitialize();
    2349           2 :     if (!poSrcLayer || !bUpdate || poDS->GetRecursionDetected())
    2350           1 :         return OGRERR_FAILURE;
    2351             : 
    2352           1 :     return poSrcLayer->CommitTransaction();
    2353             : }
    2354             : 
    2355             : /************************************************************************/
    2356             : /*                          RollbackTransaction()                       */
    2357             : /************************************************************************/
    2358             : 
    2359           2 : OGRErr OGRVRTLayer::RollbackTransaction()
    2360             : {
    2361           2 :     if (!bHasFullInitialized)
    2362           1 :         FullInitialize();
    2363           2 :     if (!poSrcLayer || !bUpdate || poDS->GetRecursionDetected())
    2364           1 :         return OGRERR_FAILURE;
    2365             : 
    2366           1 :     return poSrcLayer->RollbackTransaction();
    2367             : }
    2368             : 
    2369             : /************************************************************************/
    2370             : /*                          SetIgnoredFields()                          */
    2371             : /************************************************************************/
    2372             : 
    2373        1672 : OGRErr OGRVRTLayer::SetIgnoredFields(CSLConstList papszFields)
    2374             : {
    2375        1672 :     if (!bHasFullInitialized)
    2376           1 :         FullInitialize();
    2377        1672 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2378          98 :         return OGRERR_FAILURE;
    2379             : 
    2380        1574 :     if (!poSrcLayer->TestCapability(OLCIgnoreFields))
    2381           6 :         return OGRERR_FAILURE;
    2382             : 
    2383        1568 :     OGRErr eErr = OGRLayer::SetIgnoredFields(papszFields);
    2384        1568 :     if (eErr != OGRERR_NONE)
    2385           0 :         return eErr;
    2386             : 
    2387        3136 :     CPLStringList aosFieldsSrc;
    2388             : 
    2389             :     // Translate explicitly ignored fields of VRT layers to their equivalent
    2390             :     // source fields.
    2391        3793 :     for (const char *pszFieldName : cpl::Iterate(papszFields))
    2392             :     {
    2393        2225 :         if (EQUAL(pszFieldName, "OGR_GEOMETRY") ||
    2394        2204 :             EQUAL(pszFieldName, "OGR_STYLE"))
    2395             :         {
    2396          21 :             aosFieldsSrc.AddString(pszFieldName);
    2397             :         }
    2398             :         else
    2399             :         {
    2400             :             int iVRTField =
    2401        2204 :                 GetFieldIndexCaseSensitiveFirst(GetLayerDefn(), pszFieldName);
    2402        2204 :             if (iVRTField >= 0)
    2403             :             {
    2404        1511 :                 int iSrcField = anSrcField[iVRTField];
    2405        1511 :                 if (iSrcField >= 0)
    2406             :                 {
    2407             :                     // If we are asked to ignore x or y for a
    2408             :                     // VGS_PointFromColumns geometry field, we must NOT pass
    2409             :                     // that order to the underlying layer.
    2410        1511 :                     bool bOKToIgnore = true;
    2411        5997 :                     for (int iGeomVRTField = 0;
    2412        5997 :                          iGeomVRTField < GetLayerDefn()->GetGeomFieldCount();
    2413             :                          iGeomVRTField++)
    2414             :                     {
    2415        4488 :                         if (iSrcField ==
    2416        4488 :                                 apoGeomFieldProps[iGeomVRTField]->iGeomXField ||
    2417             :                             iSrcField ==
    2418        4487 :                                 apoGeomFieldProps[iGeomVRTField]->iGeomYField ||
    2419             :                             iSrcField ==
    2420       13461 :                                 apoGeomFieldProps[iGeomVRTField]->iGeomZField ||
    2421             :                             iSrcField ==
    2422        4486 :                                 apoGeomFieldProps[iGeomVRTField]->iGeomMField)
    2423             :                         {
    2424           2 :                             bOKToIgnore = false;
    2425           2 :                             break;
    2426             :                         }
    2427             :                     }
    2428        1511 :                     if (bOKToIgnore)
    2429             :                     {
    2430             :                         const OGRFieldDefn *poSrcDefn =
    2431        1509 :                             GetSrcLayerDefn()->GetFieldDefn(iSrcField);
    2432        1509 :                         aosFieldsSrc.AddString(poSrcDefn->GetNameRef());
    2433             :                     }
    2434             :                 }
    2435             :             }
    2436             :             else
    2437             :             {
    2438         693 :                 iVRTField = GetLayerDefn()->GetGeomFieldIndex(pszFieldName);
    2439        1386 :                 if (iVRTField >= 0 &&
    2440         693 :                     apoGeomFieldProps[iVRTField]->eGeometryStyle == VGS_Direct)
    2441             :                 {
    2442         692 :                     int iSrcField = apoGeomFieldProps[iVRTField]->iGeomField;
    2443         692 :                     if (iSrcField >= 0)
    2444             :                     {
    2445             :                         const OGRGeomFieldDefn *poSrcDefn =
    2446         692 :                             GetSrcLayerDefn()->GetGeomFieldDefn(iSrcField);
    2447         692 :                         aosFieldsSrc.AddString(poSrcDefn->GetNameRef());
    2448             :                     }
    2449             :                 }
    2450             :             }
    2451             :         }
    2452             :     }
    2453             : 
    2454             :     // Add source fields that are not referenced by VRT layer.
    2455        3136 :     std::vector<bool> abSrcFieldUsed(GetSrcLayerDefn()->GetFieldCount());
    2456        7670 :     for (int iVRTField = 0; iVRTField < GetLayerDefn()->GetFieldCount();
    2457             :          iVRTField++)
    2458             :     {
    2459        6102 :         const int iSrcField = anSrcField[iVRTField];
    2460        6102 :         if (iSrcField >= 0)
    2461        6099 :             abSrcFieldUsed[iSrcField] = true;
    2462             :     }
    2463        4870 :     for (int iVRTField = 0; iVRTField < GetLayerDefn()->GetGeomFieldCount();
    2464             :          iVRTField++)
    2465             :     {
    2466             :         OGRVRTGeometryStyle eGeometryStyle =
    2467        3302 :             apoGeomFieldProps[iVRTField]->eGeometryStyle;
    2468             :         // For a VGS_PointFromColumns geometry field, we must not ignore
    2469             :         // the fields that help building it.
    2470        3302 :         if (eGeometryStyle == VGS_PointFromColumns)
    2471             :         {
    2472          75 :             int iSrcField = apoGeomFieldProps[iVRTField]->iGeomXField;
    2473          75 :             if (iSrcField >= 0)
    2474          75 :                 abSrcFieldUsed[iSrcField] = true;
    2475          75 :             iSrcField = apoGeomFieldProps[iVRTField]->iGeomYField;
    2476          75 :             if (iSrcField >= 0)
    2477          75 :                 abSrcFieldUsed[iSrcField] = true;
    2478          75 :             iSrcField = apoGeomFieldProps[iVRTField]->iGeomZField;
    2479          75 :             if (iSrcField >= 0)
    2480          54 :                 abSrcFieldUsed[iSrcField] = true;
    2481          75 :             iSrcField = apoGeomFieldProps[iVRTField]->iGeomMField;
    2482          75 :             if (iSrcField >= 0)
    2483           1 :                 abSrcFieldUsed[iSrcField] = true;
    2484             :         }
    2485             :         // Similarly for other kinds of geometry fields.
    2486        3227 :         else if (eGeometryStyle == VGS_WKT || eGeometryStyle == VGS_WKB ||
    2487             :                  eGeometryStyle == VGS_Shape)
    2488             :         {
    2489          58 :             int iSrcField = apoGeomFieldProps[iVRTField]->iGeomField;
    2490          58 :             if (iSrcField >= 0)
    2491          58 :                 abSrcFieldUsed[iSrcField] = true;
    2492             :         }
    2493             :     }
    2494        1568 :     if (iStyleField >= 0)
    2495           4 :         abSrcFieldUsed[iStyleField] = true;
    2496        1568 :     if (iFIDField >= 0)
    2497          28 :         abSrcFieldUsed[iFIDField] = true;
    2498        7765 :     for (int iSrcField = 0; iSrcField < GetSrcLayerDefn()->GetFieldCount();
    2499             :          iSrcField++)
    2500             :     {
    2501        6197 :         if (!abSrcFieldUsed[iSrcField])
    2502             :         {
    2503             :             const OGRFieldDefn *poSrcDefn =
    2504          40 :                 GetSrcLayerDefn()->GetFieldDefn(iSrcField);
    2505          40 :             aosFieldsSrc.AddString(poSrcDefn->GetNameRef());
    2506             :         }
    2507             :     }
    2508             : 
    2509             :     // Add source geometry fields that are not referenced by VRT layer.
    2510        1568 :     abSrcFieldUsed.clear();
    2511        1568 :     abSrcFieldUsed.resize(GetSrcLayerDefn()->GetGeomFieldCount());
    2512        4870 :     for (int iVRTField = 0; iVRTField < GetLayerDefn()->GetGeomFieldCount();
    2513             :          iVRTField++)
    2514             :     {
    2515        3302 :         if (apoGeomFieldProps[iVRTField]->eGeometryStyle == VGS_Direct)
    2516             :         {
    2517        3169 :             const int iSrcField = apoGeomFieldProps[iVRTField]->iGeomField;
    2518        3169 :             if (iSrcField >= 0)
    2519        3169 :                 abSrcFieldUsed[iSrcField] = true;
    2520             :         }
    2521             :     }
    2522        4895 :     for (int iSrcField = 0; iSrcField < GetSrcLayerDefn()->GetGeomFieldCount();
    2523             :          iSrcField++)
    2524             :     {
    2525        3327 :         if (!abSrcFieldUsed[iSrcField])
    2526             :         {
    2527             :             const OGRGeomFieldDefn *poSrcDefn =
    2528         158 :                 GetSrcLayerDefn()->GetGeomFieldDefn(iSrcField);
    2529         158 :             aosFieldsSrc.AddString(poSrcDefn->GetNameRef());
    2530             :         }
    2531             :     }
    2532             : 
    2533        1568 :     return poSrcLayer->SetIgnoredFields(aosFieldsSrc.List());
    2534             : }
    2535             : 
    2536             : /************************************************************************/
    2537             : /*                          GetSrcDataset()                             */
    2538             : /************************************************************************/
    2539             : 
    2540           7 : GDALDataset *OGRVRTLayer::GetSrcDataset()
    2541             : {
    2542           7 :     if (!bHasFullInitialized)
    2543           0 :         FullInitialize();
    2544           7 :     if (!poSrcLayer || poDS->GetRecursionDetected())
    2545           0 :         return nullptr;
    2546           7 :     return poSrcDS;
    2547             : }

Generated by: LCOV version 1.14