LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vrt - ogrvrtlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1127 1216 92.7 %
Date: 2025-05-31 00:00:17 Functions: 35 35 100.0 %

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

Generated by: LCOV version 1.14