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

Generated by: LCOV version 1.14