LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vrt - ogrvrtlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1139 1231 92.5 %
Date: 2024-11-21 22:18:42 Functions: 37 37 100.0 %

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

Generated by: LCOV version 1.14