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

Generated by: LCOV version 1.14