LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vrt - ogrvrtlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1137 1229 92.5 %
Date: 2024-04-29 12:21:24 Functions: 37 37 100.0 %

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

Generated by: LCOV version 1.14