LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1597 2043 78.2 %
Date: 2025-02-18 14:19:29 Functions: 128 147 87.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The generic portions of the OGRSFLayer class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
       9             :  * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogrsf_frmts.h"
      15             : #include "ogr_api.h"
      16             : #include "ogr_p.h"
      17             : #include "ogr_attrind.h"
      18             : #include "ogr_swq.h"
      19             : #include "ograpispy.h"
      20             : #include "ogr_wkb.h"
      21             : #include "ogrlayer_private.h"
      22             : 
      23             : #include "cpl_time.h"
      24             : #include <cassert>
      25             : #include <cmath>
      26             : #include <limits>
      27             : #include <set>
      28             : 
      29             : /************************************************************************/
      30             : /*                              OGRLayer()                              */
      31             : /************************************************************************/
      32             : 
      33       69112 : OGRLayer::OGRLayer()
      34       69112 :     : m_poPrivate(new Private()), m_bFilterIsEnvelope(FALSE),
      35             :       m_poFilterGeom(nullptr),
      36             :       m_pPreparedFilterGeom(nullptr), m_sFilterEnvelope{},
      37             :       m_iGeomFieldFilter(0), m_poStyleTable(nullptr), m_poAttrQuery(nullptr),
      38             :       m_pszAttrQueryString(nullptr), m_poAttrIndex(nullptr), m_nRefCount(0),
      39      138224 :       m_nFeaturesRead(0)
      40             : {
      41       69112 : }
      42             : 
      43             : /************************************************************************/
      44             : /*                             ~OGRLayer()                              */
      45             : /************************************************************************/
      46             : 
      47       69095 : OGRLayer::~OGRLayer()
      48             : 
      49             : {
      50       69095 :     if (m_poStyleTable)
      51             :     {
      52          11 :         delete m_poStyleTable;
      53          11 :         m_poStyleTable = nullptr;
      54             :     }
      55             : 
      56       69095 :     if (m_poAttrIndex != nullptr)
      57             :     {
      58         166 :         delete m_poAttrIndex;
      59         166 :         m_poAttrIndex = nullptr;
      60             :     }
      61             : 
      62       69095 :     if (m_poAttrQuery != nullptr)
      63             :     {
      64         634 :         delete m_poAttrQuery;
      65         634 :         m_poAttrQuery = nullptr;
      66             :     }
      67             : 
      68       69095 :     CPLFree(m_pszAttrQueryString);
      69             : 
      70       69095 :     if (m_poFilterGeom)
      71             :     {
      72         864 :         delete m_poFilterGeom;
      73         864 :         m_poFilterGeom = nullptr;
      74             :     }
      75             : 
      76       69095 :     if (m_pPreparedFilterGeom != nullptr)
      77             :     {
      78         864 :         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
      79         864 :         m_pPreparedFilterGeom = nullptr;
      80             :     }
      81             : 
      82       69095 :     if (m_poSharedArrowArrayStreamPrivateData != nullptr)
      83             :     {
      84         677 :         m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
      85             :     }
      86       69095 : }
      87             : 
      88             : /************************************************************************/
      89             : /*                             Reference()                              */
      90             : /************************************************************************/
      91             : 
      92           0 : int OGRLayer::Reference()
      93             : 
      94             : {
      95           0 :     return ++m_nRefCount;
      96             : }
      97             : 
      98             : /************************************************************************/
      99             : /*                          OGR_L_Reference()                           */
     100             : /************************************************************************/
     101             : 
     102           0 : int OGR_L_Reference(OGRLayerH hLayer)
     103             : 
     104             : {
     105           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_Reference", 0);
     106             : 
     107           0 :     return OGRLayer::FromHandle(hLayer)->Reference();
     108             : }
     109             : 
     110             : /************************************************************************/
     111             : /*                            Dereference()                             */
     112             : /************************************************************************/
     113             : 
     114           0 : int OGRLayer::Dereference()
     115             : 
     116             : {
     117           0 :     return --m_nRefCount;
     118             : }
     119             : 
     120             : /************************************************************************/
     121             : /*                         OGR_L_Dereference()                          */
     122             : /************************************************************************/
     123             : 
     124           0 : int OGR_L_Dereference(OGRLayerH hLayer)
     125             : 
     126             : {
     127           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_Dereference", 0);
     128             : 
     129           0 :     return OGRLayer::FromHandle(hLayer)->Dereference();
     130             : }
     131             : 
     132             : /************************************************************************/
     133             : /*                            GetRefCount()                             */
     134             : /************************************************************************/
     135             : 
     136           0 : int OGRLayer::GetRefCount() const
     137             : 
     138             : {
     139           0 :     return m_nRefCount;
     140             : }
     141             : 
     142             : /************************************************************************/
     143             : /*                         OGR_L_GetRefCount()                          */
     144             : /************************************************************************/
     145             : 
     146           0 : int OGR_L_GetRefCount(OGRLayerH hLayer)
     147             : 
     148             : {
     149           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetRefCount", 0);
     150             : 
     151           0 :     return OGRLayer::FromHandle(hLayer)->GetRefCount();
     152             : }
     153             : 
     154             : /************************************************************************/
     155             : /*                         GetFeatureCount()                            */
     156             : /************************************************************************/
     157             : 
     158       13831 : GIntBig OGRLayer::GetFeatureCount(int bForce)
     159             : 
     160             : {
     161       13831 :     if (!bForce)
     162           1 :         return -1;
     163             : 
     164       13830 :     GIntBig nFeatureCount = 0;
     165       55681 :     for (auto &&poFeature : *this)
     166             :     {
     167       41851 :         CPL_IGNORE_RET_VAL(poFeature.get());
     168       41851 :         nFeatureCount++;
     169             :     }
     170       13830 :     ResetReading();
     171             : 
     172       13830 :     return nFeatureCount;
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*                      OGR_L_GetFeatureCount()                         */
     177             : /************************************************************************/
     178             : 
     179       36815 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
     180             : 
     181             : {
     182       36815 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
     183             : 
     184             : #ifdef OGRAPISPY_ENABLED
     185       36815 :     if (bOGRAPISpyEnabled)
     186           2 :         OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
     187             : #endif
     188             : 
     189       36815 :     return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
     190             : }
     191             : 
     192             : /************************************************************************/
     193             : /*                            GetExtent()                               */
     194             : /************************************************************************/
     195             : 
     196             : /**
     197             :  \brief Fetch the extent of this layer.
     198             : 
     199             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     200             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     201             :  will be returned indicating that the extent isn't know.  If bForce is
     202             :  TRUE then some implementations will actually scan the entire layer once
     203             :  to compute the MBR of all the features in the layer.
     204             : 
     205             :  Depending on the drivers, the returned extent may or may not take the
     206             :  spatial filter into account.  So it is safer to call GetExtent() without
     207             :  setting a spatial filter.
     208             : 
     209             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     210             :  no meaningful extents could be collected.
     211             : 
     212             :  Note that some implementations of this method may alter the read cursor
     213             :  of the layer.
     214             : 
     215             :  This method is the same as the C function OGR_L_GetExtent().
     216             : 
     217             :  @param psExtent the structure in which the extent value will be returned.
     218             :  @param bForce Flag indicating whether the extent should be computed even
     219             :  if it is expensive.
     220             : 
     221             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     222             : */
     223             : 
     224       14994 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
     225             : {
     226       14994 :     return GetExtent(0, psExtent, bForce);
     227             : }
     228             : 
     229             : /**
     230             :  \brief Fetch the extent of this layer, on the specified geometry field.
     231             : 
     232             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     233             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     234             :  will be returned indicating that the extent isn't know.  If bForce is
     235             :  TRUE then some implementations will actually scan the entire layer once
     236             :  to compute the MBR of all the features in the layer.
     237             : 
     238             :  Depending on the drivers, the returned extent may or may not take the
     239             :  spatial filter into account.  So it is safer to call GetExtent() without
     240             :  setting a spatial filter.
     241             : 
     242             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     243             :  no meaningful extents could be collected.
     244             : 
     245             :  Note that some implementations of this method may alter the read cursor
     246             :  of the layer.
     247             : 
     248             :  This method is the same as the C function OGR_L_GetExtentEx().
     249             : 
     250             :  @param iGeomField the index of the geometry field on which to compute the extent.
     251             :  @param psExtent the structure in which the extent value will be returned.
     252             :  @param bForce Flag indicating whether the extent should be computed even
     253             :  if it is expensive.
     254             : 
     255             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     256             : 
     257             : */
     258             : 
     259       17073 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
     260             : {
     261       17073 :     psExtent->MinX = 0.0;
     262       17073 :     psExtent->MaxX = 0.0;
     263       17073 :     psExtent->MinY = 0.0;
     264       17073 :     psExtent->MaxY = 0.0;
     265             : 
     266             :     /* -------------------------------------------------------------------- */
     267             :     /*      If this layer has a none geometry type, then we can             */
     268             :     /*      reasonably assume there are not extents available.              */
     269             :     /* -------------------------------------------------------------------- */
     270       33372 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
     271       16299 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
     272             :     {
     273         774 :         if (iGeomField != 0)
     274             :         {
     275         608 :             CPLError(CE_Failure, CPLE_AppDefined,
     276             :                      "Invalid geometry field index : %d", iGeomField);
     277             :         }
     278         774 :         return OGRERR_FAILURE;
     279             :     }
     280             : 
     281       16299 :     return IGetExtent(iGeomField, psExtent, bForce);
     282             : }
     283             : 
     284             : /************************************************************************/
     285             : /*                            IGetExtent()                              */
     286             : /************************************************************************/
     287             : 
     288             : /**
     289             :  \brief Fetch the extent of this layer, on the specified geometry field.
     290             : 
     291             :  Virtual method implemented by drivers since 3.11. In previous versions,
     292             :  GetExtent() itself was the virtual method.
     293             : 
     294             :  Driver implementations, when wanting to call the base method, must take
     295             :  care of calling OGRLayer::IGetExtent() (and note the public method without
     296             :  the leading I).
     297             : 
     298             :  @param iGeomField 0-based index of the geometry field to consider.
     299             :  @param psExtent the computed extent of the layer.
     300             :  @param bForce if TRUE, the extent will be computed even if all the
     301             :         layer features have to be fetched.
     302             :  @return OGRERR_NONE on success or an error code in case of failure.
     303             :  @since GDAL 3.11
     304             : */
     305             : 
     306         415 : OGRErr OGRLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
     307             : 
     308             : {
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      If not forced, we should avoid having to scan all the           */
     311             :     /*      features and just return a failure.                             */
     312             :     /* -------------------------------------------------------------------- */
     313         415 :     if (!bForce)
     314           1 :         return OGRERR_FAILURE;
     315             : 
     316             :     /* -------------------------------------------------------------------- */
     317             :     /*      OK, we hate to do this, but go ahead and read through all       */
     318             :     /*      the features to collect geometries and build extents.           */
     319             :     /* -------------------------------------------------------------------- */
     320         414 :     OGREnvelope oEnv;
     321         414 :     bool bExtentSet = false;
     322             : 
     323        9582 :     for (auto &&poFeature : *this)
     324             :     {
     325        9168 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     326        9168 :         if (poGeom == nullptr || poGeom->IsEmpty())
     327             :         {
     328             :             /* Do nothing */
     329             :         }
     330        8863 :         else if (!bExtentSet)
     331             :         {
     332         364 :             poGeom->getEnvelope(psExtent);
     333         728 :             if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
     334         364 :                   std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
     335             :             {
     336         364 :                 bExtentSet = true;
     337             :             }
     338             :         }
     339             :         else
     340             :         {
     341        8499 :             poGeom->getEnvelope(&oEnv);
     342        8499 :             if (oEnv.MinX < psExtent->MinX)
     343         301 :                 psExtent->MinX = oEnv.MinX;
     344        8499 :             if (oEnv.MinY < psExtent->MinY)
     345         440 :                 psExtent->MinY = oEnv.MinY;
     346        8499 :             if (oEnv.MaxX > psExtent->MaxX)
     347         877 :                 psExtent->MaxX = oEnv.MaxX;
     348        8499 :             if (oEnv.MaxY > psExtent->MaxY)
     349         851 :                 psExtent->MaxY = oEnv.MaxY;
     350             :         }
     351             :     }
     352         414 :     ResetReading();
     353             : 
     354         414 :     return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
     355             : }
     356             : 
     357             : /************************************************************************/
     358             : /*                          OGR_L_GetExtent()                           */
     359             : /************************************************************************/
     360             : 
     361             : /**
     362             :  \brief Fetch the extent of this layer.
     363             : 
     364             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     365             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     366             :  will be returned indicating that the extent isn't know.  If bForce is
     367             :  TRUE then some implementations will actually scan the entire layer once
     368             :  to compute the MBR of all the features in the layer.
     369             : 
     370             :  Depending on the drivers, the returned extent may or may not take the
     371             :  spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
     372             :  setting a spatial filter.
     373             : 
     374             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     375             :  no meaningful extents could be collected.
     376             : 
     377             :  Note that some implementations of this method may alter the read cursor
     378             :  of the layer.
     379             : 
     380             :  This function is the same as the C++ method OGRLayer::GetExtent().
     381             : 
     382             :  @param hLayer handle to the layer from which to get extent.
     383             :  @param psExtent the structure in which the extent value will be returned.
     384             :  @param bForce Flag indicating whether the extent should be computed even
     385             :  if it is expensive.
     386             : 
     387             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     388             : 
     389             : */
     390             : 
     391          60 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
     392             : 
     393             : {
     394          60 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
     395             : 
     396             : #ifdef OGRAPISPY_ENABLED
     397          60 :     if (bOGRAPISpyEnabled)
     398           0 :         OGRAPISpy_L_GetExtent(hLayer, bForce);
     399             : #endif
     400             : 
     401          60 :     return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
     402          60 :                                                    bForce != FALSE);
     403             : }
     404             : 
     405             : /************************************************************************/
     406             : /*                         OGR_L_GetExtentEx()                          */
     407             : /************************************************************************/
     408             : 
     409             : /**
     410             :  \brief Fetch the extent of this layer, on the specified geometry field.
     411             : 
     412             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     413             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     414             :  will be returned indicating that the extent isn't know.  If bForce is
     415             :  TRUE then some implementations will actually scan the entire layer once
     416             :  to compute the MBR of all the features in the layer.
     417             : 
     418             :  Depending on the drivers, the returned extent may or may not take the
     419             :  spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
     420             :  setting a spatial filter.
     421             : 
     422             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     423             :  no meaningful extents could be collected.
     424             : 
     425             :  Note that some implementations of this method may alter the read cursor
     426             :  of the layer.
     427             : 
     428             :  This function is the same as the C++ method OGRLayer::GetExtent().
     429             : 
     430             :  @param hLayer handle to the layer from which to get extent.
     431             :  @param iGeomField the index of the geometry field on which to compute the extent.
     432             :  @param psExtent the structure in which the extent value will be returned.
     433             :  @param bForce Flag indicating whether the extent should be computed even
     434             :  if it is expensive.
     435             : 
     436             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     437             : 
     438             : */
     439         372 : OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
     440             :                          OGREnvelope *psExtent, int bForce)
     441             : 
     442             : {
     443         372 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
     444             : 
     445             : #ifdef OGRAPISPY_ENABLED
     446         372 :     if (bOGRAPISpyEnabled)
     447           4 :         OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
     448             : #endif
     449             : 
     450         372 :     return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
     451         372 :                                                    bForce != FALSE);
     452             : }
     453             : 
     454             : /************************************************************************/
     455             : /*                            GetExtent3D()                             */
     456             : /************************************************************************/
     457             : 
     458             : /**
     459             :  \brief Fetch the 3D extent of this layer, on the specified geometry field.
     460             : 
     461             :  Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
     462             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     463             :  will be returned indicating that the extent isn't know.  If bForce is
     464             :  TRUE then some implementations will actually scan the entire layer once
     465             :  to compute the MBR of all the features in the layer.
     466             : 
     467             :  (Contrarty to GetExtent() 2D), the returned extent will always take into
     468             :  account the attribute and spatial filters that may be installed.
     469             : 
     470             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     471             :  no meaningful extents could be collected.
     472             : 
     473             :  For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
     474             :  fields will be respectively set to +Infinity and -Infinity.
     475             : 
     476             :  Note that some implementations of this method may alter the read cursor
     477             :  of the layer.
     478             : 
     479             :  This function is the same as the C function OGR_L_GetExtent3D().
     480             : 
     481             :  @param iGeomField 0-based index of the geometry field to consider.
     482             :  @param psExtent3D the computed 3D extent of the layer.
     483             :  @param bForce if TRUE, the extent will be computed even if all the
     484             :         layer features have to be fetched.
     485             :  @return OGRERR_NONE on success or an error code in case of failure.
     486             :  @since GDAL 3.9
     487             : */
     488             : 
     489          65 : OGRErr OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
     490             :                              bool bForce)
     491             : 
     492             : {
     493          65 :     psExtent3D->MinX = 0.0;
     494          65 :     psExtent3D->MaxX = 0.0;
     495          65 :     psExtent3D->MinY = 0.0;
     496          65 :     psExtent3D->MaxY = 0.0;
     497          65 :     psExtent3D->MinZ = std::numeric_limits<double>::infinity();
     498          65 :     psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
     499             : 
     500             :     /* -------------------------------------------------------------------- */
     501             :     /*      If this layer has a none geometry type, then we can             */
     502             :     /*      reasonably assume there are not extents available.              */
     503             :     /* -------------------------------------------------------------------- */
     504         129 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
     505          64 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
     506             :     {
     507           1 :         if (iGeomField != 0)
     508             :         {
     509           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     510             :                      "Invalid geometry field index : %d", iGeomField);
     511             :         }
     512           1 :         return OGRERR_FAILURE;
     513             :     }
     514             : 
     515          64 :     return IGetExtent3D(iGeomField, psExtent3D, bForce);
     516             : }
     517             : 
     518             : /************************************************************************/
     519             : /*                           IGetExtent3D()                             */
     520             : /************************************************************************/
     521             : 
     522             : /**
     523             :  \brief Fetch the 3D extent of this layer, on the specified geometry field.
     524             : 
     525             :  See GetExtent3D() documentation.
     526             : 
     527             :  Virtual method implemented by drivers since 3.11. In previous versions,
     528             :  GetExtent3D() itself was the virtual method.
     529             : 
     530             :  Driver implementations, when wanting to call the base method, must take
     531             :  care of calling OGRLayer::IGetExtent3D() (and note the public method without
     532             :  the leading I).
     533             : 
     534             :  @param iGeomField 0-based index of the geometry field to consider.
     535             :  @param psExtent3D the computed 3D extent of the layer.
     536             :  @param bForce if TRUE, the extent will be computed even if all the
     537             :         layer features have to be fetched.
     538             :  @return OGRERR_NONE on success or an error code in case of failure.
     539             :  @since GDAL 3.11
     540             : */
     541             : 
     542          27 : OGRErr OGRLayer::IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
     543             :                               bool bForce)
     544             : 
     545             : {
     546             :     /* -------------------------------------------------------------------- */
     547             :     /*      If not forced, we should avoid having to scan all the           */
     548             :     /*      features and just return a failure.                             */
     549             :     /* -------------------------------------------------------------------- */
     550          27 :     if (!bForce)
     551           0 :         return OGRERR_FAILURE;
     552             : 
     553             :     /* -------------------------------------------------------------------- */
     554             :     /*      OK, we hate to do this, but go ahead and read through all       */
     555             :     /*      the features to collect geometries and build extents.           */
     556             :     /* -------------------------------------------------------------------- */
     557          27 :     OGREnvelope3D oEnv;
     558          27 :     bool bExtentSet = false;
     559             : 
     560         133 :     for (auto &&poFeature : *this)
     561             :     {
     562         106 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     563         106 :         if (poGeom == nullptr || poGeom->IsEmpty())
     564             :         {
     565             :             /* Do nothing */
     566             :         }
     567          89 :         else if (!bExtentSet)
     568             :         {
     569          27 :             poGeom->getEnvelope(psExtent3D);
     570             :             // This is required because getEnvelope initializes Z to 0 for 2D geometries
     571          27 :             if (!poGeom->Is3D())
     572             :             {
     573          20 :                 psExtent3D->MinZ = std::numeric_limits<double>::infinity();
     574          20 :                 psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
     575             :             }
     576          27 :             bExtentSet = true;
     577             :         }
     578             :         else
     579             :         {
     580          62 :             poGeom->getEnvelope(&oEnv);
     581             :             // This is required because getEnvelope initializes Z to 0 for 2D geometries
     582          62 :             if (!poGeom->Is3D())
     583             :             {
     584          53 :                 oEnv.MinZ = std::numeric_limits<double>::infinity();
     585          53 :                 oEnv.MaxZ = -std::numeric_limits<double>::infinity();
     586             :             }
     587             :             // Merge handles infinity correctly
     588          62 :             psExtent3D->Merge(oEnv);
     589             :         }
     590             :     }
     591          27 :     ResetReading();
     592             : 
     593          27 :     return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
     594             : }
     595             : 
     596             : /************************************************************************/
     597             : /*                          OGR_L_GetExtent3D()                         */
     598             : /************************************************************************/
     599             : 
     600             : /**
     601             :  \brief Fetch the 3D extent of this layer, on the specified geometry field.
     602             : 
     603             :  Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
     604             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     605             :  will be returned indicating that the extent isn't know.  If bForce is
     606             :  TRUE then some implementations will actually scan the entire layer once
     607             :  to compute the MBR of all the features in the layer.
     608             : 
     609             :  (Contrarty to GetExtent() 2D), the returned extent will always take into
     610             :  account the attribute and spatial filters that may be installed.
     611             : 
     612             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     613             :  no meaningful extents could be collected.
     614             : 
     615             :  For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
     616             :  fields will be respectively set to +Infinity and -Infinity.
     617             : 
     618             :  Note that some implementations of this method may alter the read cursor
     619             :  of the layer.
     620             : 
     621             :  This function is the same as the C++ method OGRLayer::GetExtent3D().
     622             : 
     623             :  @param hLayer the layer to consider.
     624             :  @param iGeomField 0-based index of the geometry field to consider.
     625             :  @param psExtent3D the computed 3D extent of the layer.
     626             :  @param bForce if TRUE, the extent will be computed even if all the
     627             :         layer features have to be fetched.
     628             :  @return OGRERR_NONE on success or an error code in case of failure.
     629             :  @since GDAL 3.9
     630             : */
     631             : 
     632          60 : OGRErr OGR_L_GetExtent3D(OGRLayerH hLayer, int iGeomField,
     633             :                          OGREnvelope3D *psExtent3D, int bForce)
     634             : 
     635             : {
     636          60 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent3D", OGRERR_INVALID_HANDLE);
     637             : 
     638             : #ifdef OGRAPISPY_ENABLED
     639          60 :     if (bOGRAPISpyEnabled)
     640           0 :         OGRAPISpy_L_GetExtent3D(hLayer, iGeomField, bForce);
     641             : #endif
     642             : 
     643          60 :     return OGRLayer::FromHandle(hLayer)->GetExtent3D(iGeomField, psExtent3D,
     644          60 :                                                      bForce != FALSE);
     645             : }
     646             : 
     647             : /************************************************************************/
     648             : /*                         SetAttributeFilter()                         */
     649             : /************************************************************************/
     650             : 
     651       14805 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
     652             : 
     653             : {
     654       14805 :     CPLFree(m_pszAttrQueryString);
     655       14805 :     m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
     656             : 
     657             :     /* -------------------------------------------------------------------- */
     658             :     /*      Are we just clearing any existing query?                        */
     659             :     /* -------------------------------------------------------------------- */
     660       14805 :     if (pszQuery == nullptr || strlen(pszQuery) == 0)
     661             :     {
     662        9827 :         if (m_poAttrQuery)
     663             :         {
     664        2834 :             delete m_poAttrQuery;
     665        2834 :             m_poAttrQuery = nullptr;
     666        2834 :             ResetReading();
     667             :         }
     668        9827 :         return OGRERR_NONE;
     669             :     }
     670             : 
     671             :     /* -------------------------------------------------------------------- */
     672             :     /*      Or are we installing a new query?                               */
     673             :     /* -------------------------------------------------------------------- */
     674             :     OGRErr eErr;
     675             : 
     676        4978 :     if (!m_poAttrQuery)
     677        3527 :         m_poAttrQuery = new OGRFeatureQuery();
     678             : 
     679        4978 :     eErr = m_poAttrQuery->Compile(this, pszQuery);
     680        4978 :     if (eErr != OGRERR_NONE)
     681             :     {
     682           3 :         delete m_poAttrQuery;
     683           3 :         m_poAttrQuery = nullptr;
     684             :     }
     685             : 
     686        4978 :     ResetReading();
     687             : 
     688        4978 :     return eErr;
     689             : }
     690             : 
     691             : /************************************************************************/
     692             : /*                        ContainGeomSpecialField()                     */
     693             : /************************************************************************/
     694             : 
     695         274 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
     696             : {
     697         274 :     if (expr->eNodeType == SNT_COLUMN)
     698             :     {
     699          57 :         if (expr->table_index == 0 && expr->field_index != -1)
     700             :         {
     701          57 :             int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
     702          57 :             return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
     703         114 :                    nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
     704          57 :                    nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
     705             :         }
     706             :     }
     707         217 :     else if (expr->eNodeType == SNT_OPERATION)
     708             :     {
     709         327 :         for (int i = 0; i < expr->nSubExprCount; i++)
     710             :         {
     711         214 :             if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
     712           0 :                 return TRUE;
     713             :         }
     714             :     }
     715         217 :     return FALSE;
     716             : }
     717             : 
     718             : /************************************************************************/
     719             : /*                AttributeFilterEvaluationNeedsGeometry()              */
     720             : /************************************************************************/
     721             : 
     722             : //! @cond Doxygen_Suppress
     723          60 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
     724             : {
     725          60 :     if (!m_poAttrQuery)
     726           0 :         return FALSE;
     727             : 
     728             :     swq_expr_node *expr =
     729          60 :         static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
     730          60 :     int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
     731             : 
     732          60 :     return ContainGeomSpecialField(expr, nLayerFieldCount);
     733             : }
     734             : 
     735             : //! @endcond
     736             : 
     737             : /************************************************************************/
     738             : /*                      OGR_L_SetAttributeFilter()                      */
     739             : /************************************************************************/
     740             : 
     741        1446 : OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
     742             : 
     743             : {
     744        1446 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
     745             :                       OGRERR_INVALID_HANDLE);
     746             : 
     747             : #ifdef OGRAPISPY_ENABLED
     748        1446 :     if (bOGRAPISpyEnabled)
     749           4 :         OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
     750             : #endif
     751             : 
     752        1446 :     return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
     753             : }
     754             : 
     755             : /************************************************************************/
     756             : /*                             GetFeature()                             */
     757             : /************************************************************************/
     758             : 
     759         984 : OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
     760             : 
     761             : {
     762             :     /* Save old attribute and spatial filters */
     763             :     char *pszOldFilter =
     764         984 :         m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
     765             :     OGRGeometry *poOldFilterGeom =
     766         984 :         (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
     767         984 :     int iOldGeomFieldFilter = m_iGeomFieldFilter;
     768             :     /* Unset filters */
     769         984 :     SetAttributeFilter(nullptr);
     770         984 :     SetSpatialFilter(0, nullptr);
     771             : 
     772         984 :     OGRFeatureUniquePtr poFeature;
     773       14391 :     for (auto &&poFeatureIter : *this)
     774             :     {
     775       13407 :         if (poFeatureIter->GetFID() == nFID)
     776             :         {
     777         660 :             poFeature.swap(poFeatureIter);
     778         660 :             break;
     779             :         }
     780             :     }
     781             : 
     782             :     /* Restore filters */
     783         984 :     SetAttributeFilter(pszOldFilter);
     784         984 :     CPLFree(pszOldFilter);
     785         984 :     SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
     786         984 :     delete poOldFilterGeom;
     787             : 
     788        1968 :     return poFeature.release();
     789             : }
     790             : 
     791             : /************************************************************************/
     792             : /*                          OGR_L_GetFeature()                          */
     793             : /************************************************************************/
     794             : 
     795        2534 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
     796             : 
     797             : {
     798        2534 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
     799             : 
     800             : #ifdef OGRAPISPY_ENABLED
     801        2534 :     if (bOGRAPISpyEnabled)
     802           2 :         OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
     803             : #endif
     804             : 
     805        2534 :     return OGRFeature::ToHandle(
     806        5068 :         OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
     807             : }
     808             : 
     809             : /************************************************************************/
     810             : /*                           SetNextByIndex()                           */
     811             : /************************************************************************/
     812             : 
     813        1075 : OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
     814             : 
     815             : {
     816        1075 :     if (nIndex < 0)
     817         194 :         return OGRERR_FAILURE;
     818             : 
     819         881 :     ResetReading();
     820             : 
     821         881 :     OGRFeature *poFeature = nullptr;
     822      129350 :     while (nIndex-- > 0)
     823             :     {
     824      128663 :         poFeature = GetNextFeature();
     825      128663 :         if (poFeature == nullptr)
     826         194 :             return OGRERR_FAILURE;
     827             : 
     828      128469 :         delete poFeature;
     829             :     }
     830             : 
     831         687 :     return OGRERR_NONE;
     832             : }
     833             : 
     834             : /************************************************************************/
     835             : /*                        OGR_L_SetNextByIndex()                        */
     836             : /************************************************************************/
     837             : 
     838          39 : OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
     839             : 
     840             : {
     841          39 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
     842             : 
     843             : #ifdef OGRAPISPY_ENABLED
     844          39 :     if (bOGRAPISpyEnabled)
     845           2 :         OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
     846             : #endif
     847             : 
     848          39 :     return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
     849             : }
     850             : 
     851             : /************************************************************************/
     852             : /*                        OGR_L_GetNextFeature()                        */
     853             : /************************************************************************/
     854             : 
     855       83114 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
     856             : 
     857             : {
     858       83114 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
     859             : 
     860             : #ifdef OGRAPISPY_ENABLED
     861       83114 :     if (bOGRAPISpyEnabled)
     862           8 :         OGRAPISpy_L_GetNextFeature(hLayer);
     863             : #endif
     864             : 
     865       83114 :     return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
     866             : }
     867             : 
     868             : /************************************************************************/
     869             : /*                       ConvertGeomsIfNecessary()                      */
     870             : /************************************************************************/
     871             : 
     872      938087 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
     873             : {
     874      938087 :     if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
     875             :     {
     876             :         // One time initialization
     877        8994 :         m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
     878        8994 :         m_poPrivate->m_bSupportsCurve =
     879        8994 :             CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
     880        8994 :         m_poPrivate->m_bSupportsM =
     881        8994 :             CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
     882        8994 :         if (CPLTestBool(
     883             :                 CPLGetConfigOption("OGR_APPLY_GEOM_SET_PRECISION", "FALSE")))
     884             :         {
     885           2 :             const auto poFeatureDefn = GetLayerDefn();
     886           2 :             const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
     887           2 :             for (int i = 0; i < nGeomFieldCount; i++)
     888             :             {
     889           2 :                 const double dfXYResolution = poFeatureDefn->GetGeomFieldDefn(i)
     890           2 :                                                   ->GetCoordinatePrecision()
     891           2 :                                                   .dfXYResolution;
     892           4 :                 if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
     893           2 :                     OGRGeometryFactory::haveGEOS())
     894             :                 {
     895           2 :                     m_poPrivate->m_bApplyGeomSetPrecision = true;
     896           2 :                     break;
     897             :                 }
     898             :             }
     899             :         }
     900             :     }
     901             : 
     902     1787450 :     if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
     903      849365 :         m_poPrivate->m_bApplyGeomSetPrecision)
     904             :     {
     905       88724 :         const auto poFeatureDefn = GetLayerDefn();
     906       88724 :         const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
     907      176756 :         for (int i = 0; i < nGeomFieldCount; i++)
     908             :         {
     909       88032 :             OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
     910       88032 :             if (poGeom)
     911             :             {
     912      103818 :                 if (!m_poPrivate->m_bSupportsM &&
     913       18752 :                     OGR_GT_HasM(poGeom->getGeometryType()))
     914             :                 {
     915           1 :                     poGeom->setMeasured(FALSE);
     916             :                 }
     917             : 
     918      169935 :                 if (!m_poPrivate->m_bSupportsCurve &&
     919       84869 :                     OGR_GT_IsNonLinear(poGeom->getGeometryType()))
     920             :                 {
     921             :                     OGRwkbGeometryType eTargetType =
     922          23 :                         OGR_GT_GetLinear(poGeom->getGeometryType());
     923          23 :                     poGeom = OGRGeometryFactory::forceTo(
     924             :                         poFeature->StealGeometry(i), eTargetType);
     925          23 :                     poFeature->SetGeomFieldDirectly(i, poGeom);
     926          23 :                     poGeom = poFeature->GetGeomFieldRef(i);
     927             :                 }
     928             : 
     929       85066 :                 if (poGeom && m_poPrivate->m_bApplyGeomSetPrecision)
     930             :                 {
     931             :                     const double dfXYResolution =
     932           2 :                         poFeatureDefn->GetGeomFieldDefn(i)
     933           2 :                             ->GetCoordinatePrecision()
     934           2 :                             .dfXYResolution;
     935           4 :                     if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
     936           2 :                         !poGeom->hasCurveGeometry())
     937             :                     {
     938           2 :                         auto poNewGeom = poGeom->SetPrecision(dfXYResolution,
     939             :                                                               /* nFlags = */ 0);
     940           2 :                         if (poNewGeom)
     941             :                         {
     942           2 :                             poFeature->SetGeomFieldDirectly(i, poNewGeom);
     943             :                             // If there was potential further processing...
     944             :                             // poGeom = poFeature->GetGeomFieldRef(i);
     945             :                         }
     946             :                     }
     947             :                 }
     948             :             }
     949             :         }
     950             :     }
     951      938087 : }
     952             : 
     953             : /************************************************************************/
     954             : /*                             SetFeature()                             */
     955             : /************************************************************************/
     956             : 
     957        3564 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
     958             : 
     959             : {
     960        3564 :     ConvertGeomsIfNecessary(poFeature);
     961        3564 :     return ISetFeature(poFeature);
     962             : }
     963             : 
     964             : /************************************************************************/
     965             : /*                             ISetFeature()                            */
     966             : /************************************************************************/
     967             : 
     968         144 : OGRErr OGRLayer::ISetFeature(OGRFeature *)
     969             : 
     970             : {
     971         144 :     return OGRERR_UNSUPPORTED_OPERATION;
     972             : }
     973             : 
     974             : /************************************************************************/
     975             : /*                          OGR_L_SetFeature()                          */
     976             : /************************************************************************/
     977             : 
     978        2478 : OGRErr OGR_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
     979             : 
     980             : {
     981        2478 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
     982        2478 :     VALIDATE_POINTER1(hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
     983             : 
     984             : #ifdef OGRAPISPY_ENABLED
     985        2478 :     if (bOGRAPISpyEnabled)
     986           2 :         OGRAPISpy_L_SetFeature(hLayer, hFeat);
     987             : #endif
     988             : 
     989        2478 :     return OGRLayer::FromHandle(hLayer)->SetFeature(
     990        2478 :         OGRFeature::FromHandle(hFeat));
     991             : }
     992             : 
     993             : /************************************************************************/
     994             : /*                           CreateFeature()                            */
     995             : /************************************************************************/
     996             : 
     997      934416 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
     998             : 
     999             : {
    1000      934416 :     ConvertGeomsIfNecessary(poFeature);
    1001      934416 :     return ICreateFeature(poFeature);
    1002             : }
    1003             : 
    1004             : /************************************************************************/
    1005             : /*                           ICreateFeature()                            */
    1006             : /************************************************************************/
    1007             : 
    1008           0 : OGRErr OGRLayer::ICreateFeature(OGRFeature *)
    1009             : 
    1010             : {
    1011           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1012             : }
    1013             : 
    1014             : /************************************************************************/
    1015             : /*                        OGR_L_CreateFeature()                         */
    1016             : /************************************************************************/
    1017             : 
    1018      286381 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
    1019             : 
    1020             : {
    1021      286381 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
    1022      286381 :     VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
    1023             : 
    1024             : #ifdef OGRAPISPY_ENABLED
    1025      286381 :     if (bOGRAPISpyEnabled)
    1026           5 :         OGRAPISpy_L_CreateFeature(hLayer, hFeat);
    1027             : #endif
    1028             : 
    1029      286381 :     return OGRLayer::FromHandle(hLayer)->CreateFeature(
    1030      286381 :         OGRFeature::FromHandle(hFeat));
    1031             : }
    1032             : 
    1033             : /************************************************************************/
    1034             : /*                           UpsertFeature()                           */
    1035             : /************************************************************************/
    1036             : 
    1037          32 : OGRErr OGRLayer::UpsertFeature(OGRFeature *poFeature)
    1038             : 
    1039             : {
    1040          32 :     ConvertGeomsIfNecessary(poFeature);
    1041          32 :     return IUpsertFeature(poFeature);
    1042             : }
    1043             : 
    1044             : /************************************************************************/
    1045             : /*                           IUpsertFeature()                           */
    1046             : /************************************************************************/
    1047             : 
    1048           0 : OGRErr OGRLayer::IUpsertFeature(OGRFeature *)
    1049             : {
    1050           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1051             : }
    1052             : 
    1053             : /************************************************************************/
    1054             : /*                        OGR_L_UpsertFeature()                         */
    1055             : /************************************************************************/
    1056             : 
    1057          31 : OGRErr OGR_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
    1058             : 
    1059             : {
    1060          31 :     VALIDATE_POINTER1(hLayer, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
    1061          31 :     VALIDATE_POINTER1(hFeat, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
    1062             : 
    1063             : #ifdef OGRAPISPY_ENABLED
    1064          31 :     if (bOGRAPISpyEnabled)
    1065           0 :         OGRAPISpy_L_UpsertFeature(hLayer, hFeat);
    1066             : #endif
    1067             : 
    1068          31 :     return OGRLayer::FromHandle(hLayer)->UpsertFeature(
    1069          31 :         OGRFeature::FromHandle(hFeat));
    1070             : }
    1071             : 
    1072             : /************************************************************************/
    1073             : /*                           UpdateFeature()                            */
    1074             : /************************************************************************/
    1075             : 
    1076          75 : OGRErr OGRLayer::UpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
    1077             :                                const int *panUpdatedFieldsIdx,
    1078             :                                int nUpdatedGeomFieldsCount,
    1079             :                                const int *panUpdatedGeomFieldsIdx,
    1080             :                                bool bUpdateStyleString)
    1081             : 
    1082             : {
    1083          75 :     ConvertGeomsIfNecessary(poFeature);
    1084          75 :     const int nFieldCount = GetLayerDefn()->GetFieldCount();
    1085         136 :     for (int i = 0; i < nUpdatedFieldsCount; ++i)
    1086             :     {
    1087          63 :         if (panUpdatedFieldsIdx[i] < 0 || panUpdatedFieldsIdx[i] >= nFieldCount)
    1088             :         {
    1089           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    1090             :                      "Invalid panUpdatedFieldsIdx[%d] = %d", i,
    1091           2 :                      panUpdatedFieldsIdx[i]);
    1092           2 :             return OGRERR_FAILURE;
    1093             :         }
    1094             :     }
    1095          73 :     const int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
    1096          83 :     for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
    1097             :     {
    1098          12 :         if (panUpdatedGeomFieldsIdx[i] < 0 ||
    1099          11 :             panUpdatedGeomFieldsIdx[i] >= nGeomFieldCount)
    1100             :         {
    1101           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    1102             :                      "Invalid panUpdatedGeomFieldsIdx[%d] = %d", i,
    1103           2 :                      panUpdatedGeomFieldsIdx[i]);
    1104           2 :             return OGRERR_FAILURE;
    1105             :         }
    1106             :     }
    1107          71 :     return IUpdateFeature(poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
    1108             :                           nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx,
    1109          71 :                           bUpdateStyleString);
    1110             : }
    1111             : 
    1112             : /************************************************************************/
    1113             : /*                           IUpdateFeature()                           */
    1114             : /************************************************************************/
    1115             : 
    1116          28 : OGRErr OGRLayer::IUpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
    1117             :                                 const int *panUpdatedFieldsIdx,
    1118             :                                 int nUpdatedGeomFieldsCount,
    1119             :                                 const int *panUpdatedGeomFieldsIdx,
    1120             :                                 bool bUpdateStyleString)
    1121             : {
    1122          28 :     if (!TestCapability(OLCRandomWrite))
    1123           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    1124             : 
    1125             :     auto poFeatureExisting =
    1126          56 :         std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID()));
    1127          28 :     if (!poFeatureExisting)
    1128           1 :         return OGRERR_NON_EXISTING_FEATURE;
    1129             : 
    1130          52 :     for (int i = 0; i < nUpdatedFieldsCount; ++i)
    1131             :     {
    1132          25 :         poFeatureExisting->SetField(
    1133          25 :             panUpdatedFieldsIdx[i],
    1134          25 :             poFeature->GetRawFieldRef(panUpdatedFieldsIdx[i]));
    1135             :     }
    1136          29 :     for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
    1137             :     {
    1138           2 :         poFeatureExisting->SetGeomFieldDirectly(
    1139           2 :             panUpdatedGeomFieldsIdx[i],
    1140           2 :             poFeature->StealGeometry(panUpdatedGeomFieldsIdx[i]));
    1141             :     }
    1142          27 :     if (bUpdateStyleString)
    1143             :     {
    1144           0 :         poFeatureExisting->SetStyleString(poFeature->GetStyleString());
    1145             :     }
    1146          27 :     return ISetFeature(poFeatureExisting.get());
    1147             : }
    1148             : 
    1149             : /************************************************************************/
    1150             : /*                        OGR_L_UpdateFeature()                         */
    1151             : /************************************************************************/
    1152             : 
    1153          31 : OGRErr OGR_L_UpdateFeature(OGRLayerH hLayer, OGRFeatureH hFeat,
    1154             :                            int nUpdatedFieldsCount,
    1155             :                            const int *panUpdatedFieldsIdx,
    1156             :                            int nUpdatedGeomFieldsCount,
    1157             :                            const int *panUpdatedGeomFieldsIdx,
    1158             :                            bool bUpdateStyleString)
    1159             : 
    1160             : {
    1161          31 :     VALIDATE_POINTER1(hLayer, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
    1162          31 :     VALIDATE_POINTER1(hFeat, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
    1163             : 
    1164          31 :     return OGRLayer::FromHandle(hLayer)->UpdateFeature(
    1165             :         OGRFeature::FromHandle(hFeat), nUpdatedFieldsCount, panUpdatedFieldsIdx,
    1166          31 :         nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
    1167             : }
    1168             : 
    1169             : /************************************************************************/
    1170             : /*                            CreateField()                             */
    1171             : /************************************************************************/
    1172             : 
    1173          80 : OGRErr OGRLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
    1174             : 
    1175             : {
    1176             :     (void)poField;
    1177             :     (void)bApproxOK;
    1178             : 
    1179          80 :     CPLError(CE_Failure, CPLE_NotSupported,
    1180             :              "CreateField() not supported by this layer.\n");
    1181             : 
    1182          80 :     return OGRERR_UNSUPPORTED_OPERATION;
    1183             : }
    1184             : 
    1185             : /************************************************************************/
    1186             : /*                         OGR_L_CreateField()                          */
    1187             : /************************************************************************/
    1188             : 
    1189       77294 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
    1190             : 
    1191             : {
    1192       77294 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
    1193       77294 :     VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
    1194             : 
    1195             : #ifdef OGRAPISPY_ENABLED
    1196       77294 :     if (bOGRAPISpyEnabled)
    1197           6 :         OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
    1198             : #endif
    1199             : 
    1200      154588 :     return OGRLayer::FromHandle(hLayer)->CreateField(
    1201       77294 :         OGRFieldDefn::FromHandle(hField), bApproxOK);
    1202             : }
    1203             : 
    1204             : /************************************************************************/
    1205             : /*                            DeleteField()                             */
    1206             : /************************************************************************/
    1207             : 
    1208           0 : OGRErr OGRLayer::DeleteField(int iField)
    1209             : 
    1210             : {
    1211             :     (void)iField;
    1212             : 
    1213           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1214             :              "DeleteField() not supported by this layer.\n");
    1215             : 
    1216           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1217             : }
    1218             : 
    1219             : /************************************************************************/
    1220             : /*                         OGR_L_DeleteField()                          */
    1221             : /************************************************************************/
    1222             : 
    1223         372 : OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
    1224             : 
    1225             : {
    1226         372 :     VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
    1227             : 
    1228             : #ifdef OGRAPISPY_ENABLED
    1229         372 :     if (bOGRAPISpyEnabled)
    1230           2 :         OGRAPISpy_L_DeleteField(hLayer, iField);
    1231             : #endif
    1232             : 
    1233         372 :     return OGRLayer::FromHandle(hLayer)->DeleteField(iField);
    1234             : }
    1235             : 
    1236             : /************************************************************************/
    1237             : /*                           ReorderFields()                            */
    1238             : /************************************************************************/
    1239             : 
    1240           0 : OGRErr OGRLayer::ReorderFields(int *panMap)
    1241             : 
    1242             : {
    1243             :     (void)panMap;
    1244             : 
    1245           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1246             :              "ReorderFields() not supported by this layer.\n");
    1247             : 
    1248           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1249             : }
    1250             : 
    1251             : /************************************************************************/
    1252             : /*                       OGR_L_ReorderFields()                          */
    1253             : /************************************************************************/
    1254             : 
    1255          43 : OGRErr OGR_L_ReorderFields(OGRLayerH hLayer, int *panMap)
    1256             : 
    1257             : {
    1258          43 :     VALIDATE_POINTER1(hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE);
    1259             : 
    1260             : #ifdef OGRAPISPY_ENABLED
    1261          43 :     if (bOGRAPISpyEnabled)
    1262           2 :         OGRAPISpy_L_ReorderFields(hLayer, panMap);
    1263             : #endif
    1264             : 
    1265          43 :     return OGRLayer::FromHandle(hLayer)->ReorderFields(panMap);
    1266             : }
    1267             : 
    1268             : /************************************************************************/
    1269             : /*                            ReorderField()                            */
    1270             : /************************************************************************/
    1271             : 
    1272          34 : OGRErr OGRLayer::ReorderField(int iOldFieldPos, int iNewFieldPos)
    1273             : 
    1274             : {
    1275             :     OGRErr eErr;
    1276             : 
    1277          34 :     int nFieldCount = GetLayerDefn()->GetFieldCount();
    1278             : 
    1279          34 :     if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
    1280             :     {
    1281           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    1282           0 :         return OGRERR_FAILURE;
    1283             :     }
    1284          34 :     if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
    1285             :     {
    1286           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    1287           0 :         return OGRERR_FAILURE;
    1288             :     }
    1289          34 :     if (iNewFieldPos == iOldFieldPos)
    1290           0 :         return OGRERR_NONE;
    1291             : 
    1292          34 :     int *panMap = static_cast<int *>(CPLMalloc(sizeof(int) * nFieldCount));
    1293          34 :     if (iOldFieldPos < iNewFieldPos)
    1294             :     {
    1295             :         /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
    1296          15 :         int i = 0;  // Used after for.
    1297          19 :         for (; i < iOldFieldPos; i++)
    1298           4 :             panMap[i] = i;
    1299          40 :         for (; i < iNewFieldPos; i++)
    1300          25 :             panMap[i] = i + 1;
    1301          15 :         panMap[iNewFieldPos] = iOldFieldPos;
    1302          27 :         for (i = iNewFieldPos + 1; i < nFieldCount; i++)
    1303          12 :             panMap[i] = i;
    1304             :     }
    1305             :     else
    1306             :     {
    1307             :         /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
    1308          23 :         for (int i = 0; i < iNewFieldPos; i++)
    1309           4 :             panMap[i] = i;
    1310          19 :         panMap[iNewFieldPos] = iOldFieldPos;
    1311          19 :         int i = iNewFieldPos + 1;  // Used after for.
    1312          67 :         for (; i <= iOldFieldPos; i++)
    1313          48 :             panMap[i] = i - 1;
    1314          31 :         for (; i < nFieldCount; i++)
    1315          12 :             panMap[i] = i;
    1316             :     }
    1317             : 
    1318          34 :     eErr = ReorderFields(panMap);
    1319             : 
    1320          34 :     CPLFree(panMap);
    1321             : 
    1322          34 :     return eErr;
    1323             : }
    1324             : 
    1325             : /************************************************************************/
    1326             : /*                        OGR_L_ReorderField()                          */
    1327             : /************************************************************************/
    1328             : 
    1329          34 : OGRErr OGR_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos)
    1330             : 
    1331             : {
    1332          34 :     VALIDATE_POINTER1(hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE);
    1333             : 
    1334             : #ifdef OGRAPISPY_ENABLED
    1335          34 :     if (bOGRAPISpyEnabled)
    1336           2 :         OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
    1337             : #endif
    1338             : 
    1339          34 :     return OGRLayer::FromHandle(hLayer)->ReorderField(iOldFieldPos,
    1340          34 :                                                       iNewFieldPos);
    1341             : }
    1342             : 
    1343             : /************************************************************************/
    1344             : /*                           AlterFieldDefn()                           */
    1345             : /************************************************************************/
    1346             : 
    1347           0 : OGRErr OGRLayer::AlterFieldDefn(int /* iField*/,
    1348             :                                 OGRFieldDefn * /*poNewFieldDefn*/,
    1349             :                                 int /* nFlags */)
    1350             : 
    1351             : {
    1352           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1353             :              "AlterFieldDefn() not supported by this layer.\n");
    1354             : 
    1355           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1356             : }
    1357             : 
    1358             : /************************************************************************/
    1359             : /*                        OGR_L_AlterFieldDefn()                        */
    1360             : /************************************************************************/
    1361             : 
    1362         126 : OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
    1363             :                             OGRFieldDefnH hNewFieldDefn, int nFlags)
    1364             : 
    1365             : {
    1366         126 :     VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
    1367         126 :     VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
    1368             :                       OGRERR_INVALID_HANDLE);
    1369             : 
    1370             : #ifdef OGRAPISPY_ENABLED
    1371         126 :     if (bOGRAPISpyEnabled)
    1372           2 :         OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
    1373             : #endif
    1374             : 
    1375         252 :     return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
    1376         126 :         iField, OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags);
    1377             : }
    1378             : 
    1379             : /************************************************************************/
    1380             : /*                        AlterGeomFieldDefn()                          */
    1381             : /************************************************************************/
    1382             : 
    1383             : OGRErr
    1384           0 : OGRLayer::AlterGeomFieldDefn(int /* iGeomField*/,
    1385             :                              const OGRGeomFieldDefn * /*poNewGeomFieldDefn*/,
    1386             :                              int /* nFlags */)
    1387             : 
    1388             : {
    1389           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1390             :              "AlterGeomFieldDefn() not supported by this layer.\n");
    1391             : 
    1392           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1393             : }
    1394             : 
    1395             : /************************************************************************/
    1396             : /*                      OGR_L_AlterGeomFieldDefn()                      */
    1397             : /************************************************************************/
    1398             : 
    1399          33 : OGRErr OGR_L_AlterGeomFieldDefn(OGRLayerH hLayer, int iGeomField,
    1400             :                                 OGRGeomFieldDefnH hNewGeomFieldDefn, int nFlags)
    1401             : 
    1402             : {
    1403          33 :     VALIDATE_POINTER1(hLayer, "OGR_L_AlterGeomFieldDefn",
    1404             :                       OGRERR_INVALID_HANDLE);
    1405          33 :     VALIDATE_POINTER1(hNewGeomFieldDefn, "OGR_L_AlterGeomFieldDefn",
    1406             :                       OGRERR_INVALID_HANDLE);
    1407             : 
    1408          66 :     return OGRLayer::FromHandle(hLayer)->AlterGeomFieldDefn(
    1409             :         iGeomField,
    1410             :         const_cast<const OGRGeomFieldDefn *>(
    1411          33 :             OGRGeomFieldDefn::FromHandle(hNewGeomFieldDefn)),
    1412          33 :         nFlags);
    1413             : }
    1414             : 
    1415             : /************************************************************************/
    1416             : /*                         CreateGeomField()                            */
    1417             : /************************************************************************/
    1418             : 
    1419           0 : OGRErr OGRLayer::CreateGeomField(const OGRGeomFieldDefn *poField, int bApproxOK)
    1420             : 
    1421             : {
    1422             :     (void)poField;
    1423             :     (void)bApproxOK;
    1424             : 
    1425           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1426             :              "CreateGeomField() not supported by this layer.\n");
    1427             : 
    1428           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1429             : }
    1430             : 
    1431             : /************************************************************************/
    1432             : /*                        OGR_L_CreateGeomField()                       */
    1433             : /************************************************************************/
    1434             : 
    1435         120 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
    1436             :                              int bApproxOK)
    1437             : 
    1438             : {
    1439         120 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
    1440         120 :     VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
    1441             : 
    1442             : #ifdef OGRAPISPY_ENABLED
    1443         120 :     if (bOGRAPISpyEnabled)
    1444           2 :         OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
    1445             : #endif
    1446             : 
    1447         240 :     return OGRLayer::FromHandle(hLayer)->CreateGeomField(
    1448         120 :         OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
    1449             : }
    1450             : 
    1451             : /************************************************************************/
    1452             : /*                          StartTransaction()                          */
    1453             : /************************************************************************/
    1454             : 
    1455         656 : OGRErr OGRLayer::StartTransaction()
    1456             : 
    1457             : {
    1458         656 :     return OGRERR_NONE;
    1459             : }
    1460             : 
    1461             : /************************************************************************/
    1462             : /*                       OGR_L_StartTransaction()                       */
    1463             : /************************************************************************/
    1464             : 
    1465         158 : OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
    1466             : 
    1467             : {
    1468         158 :     VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
    1469             : 
    1470             : #ifdef OGRAPISPY_ENABLED
    1471         158 :     if (bOGRAPISpyEnabled)
    1472           2 :         OGRAPISpy_L_StartTransaction(hLayer);
    1473             : #endif
    1474             : 
    1475         158 :     return OGRLayer::FromHandle(hLayer)->StartTransaction();
    1476             : }
    1477             : 
    1478             : /************************************************************************/
    1479             : /*                         CommitTransaction()                          */
    1480             : /************************************************************************/
    1481             : 
    1482         612 : OGRErr OGRLayer::CommitTransaction()
    1483             : 
    1484             : {
    1485         612 :     return OGRERR_NONE;
    1486             : }
    1487             : 
    1488             : /************************************************************************/
    1489             : /*                       OGR_L_CommitTransaction()                      */
    1490             : /************************************************************************/
    1491             : 
    1492         138 : OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
    1493             : 
    1494             : {
    1495         138 :     VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
    1496             : 
    1497             : #ifdef OGRAPISPY_ENABLED
    1498         138 :     if (bOGRAPISpyEnabled)
    1499           2 :         OGRAPISpy_L_CommitTransaction(hLayer);
    1500             : #endif
    1501             : 
    1502         138 :     return OGRLayer::FromHandle(hLayer)->CommitTransaction();
    1503             : }
    1504             : 
    1505             : /************************************************************************/
    1506             : /*                        RollbackTransaction()                         */
    1507             : /************************************************************************/
    1508             : 
    1509          47 : OGRErr OGRLayer::RollbackTransaction()
    1510             : 
    1511             : {
    1512          47 :     return OGRERR_UNSUPPORTED_OPERATION;
    1513             : }
    1514             : 
    1515             : /************************************************************************/
    1516             : /*                     OGR_L_RollbackTransaction()                      */
    1517             : /************************************************************************/
    1518             : 
    1519          26 : OGRErr OGR_L_RollbackTransaction(OGRLayerH hLayer)
    1520             : 
    1521             : {
    1522          26 :     VALIDATE_POINTER1(hLayer, "OGR_L_RollbackTransaction",
    1523             :                       OGRERR_INVALID_HANDLE);
    1524             : 
    1525             : #ifdef OGRAPISPY_ENABLED
    1526          26 :     if (bOGRAPISpyEnabled)
    1527           2 :         OGRAPISpy_L_RollbackTransaction(hLayer);
    1528             : #endif
    1529             : 
    1530          26 :     return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
    1531             : }
    1532             : 
    1533             : /************************************************************************/
    1534             : /*                         OGR_L_GetLayerDefn()                         */
    1535             : /************************************************************************/
    1536             : 
    1537      131313 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
    1538             : 
    1539             : {
    1540      131313 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
    1541             : 
    1542             : #ifdef OGRAPISPY_ENABLED
    1543      131313 :     if (bOGRAPISpyEnabled)
    1544          15 :         OGRAPISpy_L_GetLayerDefn(hLayer);
    1545             : #endif
    1546             : 
    1547      131313 :     return OGRFeatureDefn::ToHandle(
    1548      262626 :         OGRLayer::FromHandle(hLayer)->GetLayerDefn());
    1549             : }
    1550             : 
    1551             : /************************************************************************/
    1552             : /*                         OGR_L_FindFieldIndex()                       */
    1553             : /************************************************************************/
    1554             : 
    1555           2 : int OGR_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
    1556             :                          int bExactMatch)
    1557             : 
    1558             : {
    1559           2 :     VALIDATE_POINTER1(hLayer, "OGR_L_FindFieldIndex", -1);
    1560             : 
    1561             : #ifdef OGRAPISPY_ENABLED
    1562           2 :     if (bOGRAPISpyEnabled)
    1563           2 :         OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
    1564             : #endif
    1565             : 
    1566           4 :     return OGRLayer::FromHandle(hLayer)->FindFieldIndex(pszFieldName,
    1567           2 :                                                         bExactMatch);
    1568             : }
    1569             : 
    1570             : /************************************************************************/
    1571             : /*                           FindFieldIndex()                           */
    1572             : /************************************************************************/
    1573             : 
    1574          78 : int OGRLayer::FindFieldIndex(const char *pszFieldName,
    1575             :                              CPL_UNUSED int bExactMatch)
    1576             : {
    1577          78 :     return GetLayerDefn()->GetFieldIndex(pszFieldName);
    1578             : }
    1579             : 
    1580             : /************************************************************************/
    1581             : /*                           GetSpatialRef()                            */
    1582             : /************************************************************************/
    1583             : 
    1584      425236 : OGRSpatialReference *OGRLayer::GetSpatialRef()
    1585             : {
    1586      425236 :     if (GetLayerDefn()->GetGeomFieldCount() > 0)
    1587             :         return const_cast<OGRSpatialReference *>(
    1588      424776 :             GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef());
    1589             :     else
    1590         460 :         return nullptr;
    1591             : }
    1592             : 
    1593             : /************************************************************************/
    1594             : /*                        OGR_L_GetSpatialRef()                         */
    1595             : /************************************************************************/
    1596             : 
    1597        1029 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
    1598             : 
    1599             : {
    1600        1029 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
    1601             : 
    1602             : #ifdef OGRAPISPY_ENABLED
    1603        1029 :     if (bOGRAPISpyEnabled)
    1604           2 :         OGRAPISpy_L_GetSpatialRef(hLayer);
    1605             : #endif
    1606             : 
    1607        1029 :     return OGRSpatialReference::ToHandle(
    1608        2058 :         OGRLayer::FromHandle(hLayer)->GetSpatialRef());
    1609             : }
    1610             : 
    1611             : /************************************************************************/
    1612             : /*                        OGR_L_TestCapability()                        */
    1613             : /************************************************************************/
    1614             : 
    1615         825 : int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
    1616             : 
    1617             : {
    1618         825 :     VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
    1619         825 :     VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
    1620             : 
    1621             : #ifdef OGRAPISPY_ENABLED
    1622         825 :     if (bOGRAPISpyEnabled)
    1623           2 :         OGRAPISpy_L_TestCapability(hLayer, pszCap);
    1624             : #endif
    1625             : 
    1626         825 :     return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
    1627             : }
    1628             : 
    1629             : /************************************************************************/
    1630             : /*                          GetSpatialFilter()                          */
    1631             : /************************************************************************/
    1632             : 
    1633         389 : OGRGeometry *OGRLayer::GetSpatialFilter()
    1634             : 
    1635             : {
    1636         389 :     return m_poFilterGeom;
    1637             : }
    1638             : 
    1639             : /************************************************************************/
    1640             : /*                       OGR_L_GetSpatialFilter()                       */
    1641             : /************************************************************************/
    1642             : 
    1643           5 : OGRGeometryH OGR_L_GetSpatialFilter(OGRLayerH hLayer)
    1644             : 
    1645             : {
    1646           5 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialFilter", nullptr);
    1647             : 
    1648             : #ifdef OGRAPISPY_ENABLED
    1649           5 :     if (bOGRAPISpyEnabled)
    1650           2 :         OGRAPISpy_L_GetSpatialFilter(hLayer);
    1651             : #endif
    1652             : 
    1653           5 :     return OGRGeometry::ToHandle(
    1654          10 :         OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
    1655             : }
    1656             : 
    1657             : /************************************************************************/
    1658             : /*             ValidateGeometryFieldIndexForSetSpatialFilter()          */
    1659             : /************************************************************************/
    1660             : 
    1661             : //! @cond Doxygen_Suppress
    1662       53268 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
    1663             :     int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
    1664             : {
    1665       53268 :     if (iGeomField == 0 && poGeomIn == nullptr &&
    1666           0 :         GetLayerDefn()->GetGeomFieldCount() == 0)
    1667             :     {
    1668             :         // Setting a null spatial filter on geometry field idx 0
    1669             :         // when there are no geometry field can't harm, and is accepted silently
    1670             :         // for backward compatibility with existing practice.
    1671             :     }
    1672      106296 :     else if (iGeomField < 0 ||
    1673       53028 :              iGeomField >= GetLayerDefn()->GetGeomFieldCount())
    1674             :     {
    1675         561 :         if (iGeomField == 0)
    1676             :         {
    1677          79 :             CPLError(
    1678             :                 CE_Failure, CPLE_AppDefined,
    1679             :                 bIsSelectLayer
    1680             :                     ? "Cannot set spatial filter: no geometry field selected."
    1681             :                     : "Cannot set spatial filter: no geometry field present in "
    1682             :                       "layer.");
    1683             :         }
    1684             :         else
    1685             :         {
    1686         482 :             CPLError(CE_Failure, CPLE_AppDefined,
    1687             :                      "Cannot set spatial filter on non-existing geometry field "
    1688             :                      "of index %d.",
    1689             :                      iGeomField);
    1690             :         }
    1691         561 :         return false;
    1692             :     }
    1693       52707 :     return true;
    1694             : }
    1695             : 
    1696             : //! @endcond
    1697             : 
    1698             : /************************************************************************/
    1699             : /*                          SetSpatialFilter()                          */
    1700             : /************************************************************************/
    1701             : 
    1702             : /**
    1703             :  \brief Set a new spatial filter.
    1704             : 
    1705             :  This method set the geometry to be used as a spatial filter when
    1706             :  fetching features via the GetNextFeature() method.  Only features that
    1707             :  geometrically intersect the filter geometry will be returned.
    1708             : 
    1709             :  Currently this test is may be inaccurately implemented, but it is
    1710             :  guaranteed that all features whose envelope (as returned by
    1711             :  OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
    1712             :  will be returned.  This can result in more shapes being returned that
    1713             :  should strictly be the case.
    1714             : 
    1715             :  Starting with GDAL 2.3, features with null or empty geometries will never
    1716             :  be considered as matching a spatial filter.
    1717             : 
    1718             :  This method makes an internal copy of the passed geometry.  The
    1719             :  passed geometry remains the responsibility of the caller, and may
    1720             :  be safely destroyed.
    1721             : 
    1722             :  For the time being the passed filter geometry should be in the same
    1723             :  SRS as the layer (as returned by OGRLayer::GetSpatialRef()).  In the
    1724             :  future this may be generalized.
    1725             : 
    1726             :  This method is the same as the C function OGR_L_SetSpatialFilter().
    1727             : 
    1728             :  @param poFilter the geometry to use as a filtering region.  NULL may
    1729             :  be passed indicating that the current spatial filter should be cleared,
    1730             :  but no new one instituted.
    1731             :  */
    1732             : 
    1733        6660 : OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
    1734             : 
    1735             : {
    1736        6660 :     return SetSpatialFilter(0, poFilter);
    1737             : }
    1738             : 
    1739             : /**
    1740             :  \brief Set a new spatial filter.
    1741             : 
    1742             :  This method set the geometry to be used as a spatial filter when
    1743             :  fetching features via the GetNextFeature() method.  Only features that
    1744             :  geometrically intersect the filter geometry will be returned.
    1745             : 
    1746             :  Currently this test is may be inaccurately implemented, but it is
    1747             :  guaranteed that all features who's envelope (as returned by
    1748             :  OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
    1749             :  will be returned.  This can result in more shapes being returned that
    1750             :  should strictly be the case.
    1751             : 
    1752             :  This method makes an internal copy of the passed geometry.  The
    1753             :  passed geometry remains the responsibility of the caller, and may
    1754             :  be safely destroyed.
    1755             : 
    1756             :  For the time being the passed filter geometry should be in the same
    1757             :  SRS as the geometry field definition it corresponds to (as returned by
    1758             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
    1759             :  future this may be generalized.
    1760             : 
    1761             :  Note that only the last spatial filter set is applied, even if several
    1762             :  successive calls are done with different iGeomField values.
    1763             : 
    1764             :  This method is the same as the C function OGR_L_SetSpatialFilterEx().
    1765             : 
    1766             :  @param iGeomField index of the geometry field on which the spatial filter
    1767             :  operates.
    1768             :  @param poFilter the geometry to use as a filtering region.  NULL may
    1769             :  be passed indicating that the current spatial filter should be cleared,
    1770             :  but no new one instituted.
    1771             : 
    1772             :  @since GDAL 1.11
    1773             :  */
    1774             : 
    1775       65567 : OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
    1776             : 
    1777             : {
    1778       65567 :     if (iGeomField == 0)
    1779             :     {
    1780      115887 :         if (poFilter &&
    1781       51793 :             !ValidateGeometryFieldIndexForSetSpatialFilter(0, poFilter))
    1782             :         {
    1783          79 :             return OGRERR_FAILURE;
    1784             :         }
    1785             :     }
    1786             :     else
    1787             :     {
    1788        1473 :         if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
    1789             :                                                            poFilter))
    1790             :         {
    1791         482 :             return OGRERR_FAILURE;
    1792             :         }
    1793             :     }
    1794             : 
    1795       65006 :     return ISetSpatialFilter(iGeomField, poFilter);
    1796             : }
    1797             : 
    1798             : /************************************************************************/
    1799             : /*                         ISetSpatialFilter()                          */
    1800             : /************************************************************************/
    1801             : 
    1802             : /**
    1803             :  \brief Set a new spatial filter.
    1804             : 
    1805             :  Virtual method implemented by drivers since 3.11. In previous versions,
    1806             :  SetSpatialFilter() / SetSpatialFilterRect() itself was the virtual method.
    1807             : 
    1808             :  Driver implementations, when wanting to call the base method, must take
    1809             :  care of calling OGRLayer::ISetSpatialFilter() (and note the public method without
    1810             :  the leading I).
    1811             : 
    1812             :  @param iGeomField index of the geometry field on which the spatial filter
    1813             :  operates.
    1814             :  @param poFilter the geometry to use as a filtering region.  NULL may
    1815             :  be passed indicating that the current spatial filter should be cleared,
    1816             :  but no new one instituted.
    1817             : 
    1818             :  @since GDAL 3.11
    1819             :  */
    1820             : 
    1821       36488 : OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
    1822             : 
    1823             : {
    1824       36488 :     m_iGeomFieldFilter = iGeomField;
    1825       36488 :     if (InstallFilter(poFilter))
    1826       28430 :         ResetReading();
    1827       36488 :     return OGRERR_NONE;
    1828             : }
    1829             : 
    1830             : /************************************************************************/
    1831             : /*                       OGR_L_SetSpatialFilter()                       */
    1832             : /************************************************************************/
    1833             : 
    1834             : /**
    1835             :  \brief Set a new spatial filter.
    1836             : 
    1837             :  This function set the geometry to be used as a spatial filter when
    1838             :  fetching features via the OGR_L_GetNextFeature() function.  Only
    1839             :  features that geometrically intersect the filter geometry will be
    1840             :  returned.
    1841             : 
    1842             :  Currently this test is may be inaccurately implemented, but it is
    1843             :  guaranteed that all features whose envelope (as returned by
    1844             :  OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
    1845             :  will be returned.  This can result in more shapes being returned that
    1846             :  should strictly be the case.
    1847             : 
    1848             :  Starting with GDAL 2.3, features with null or empty geometries will never
    1849             :  be considered as matching a spatial filter.
    1850             : 
    1851             :  This function makes an internal copy of the passed geometry.  The
    1852             :  passed geometry remains the responsibility of the caller, and may
    1853             :  be safely destroyed.
    1854             : 
    1855             :  For the time being the passed filter geometry should be in the same
    1856             :  SRS as the layer (as returned by OGR_L_GetSpatialRef()).  In the
    1857             :  future this may be generalized.
    1858             : 
    1859             :  This function is the same as the C++ method OGRLayer::SetSpatialFilter.
    1860             : 
    1861             :  @param hLayer handle to the layer on which to set the spatial filter.
    1862             :  @param hGeom handle to the geometry to use as a filtering region.  NULL may
    1863             :  be passed indicating that the current spatial filter should be cleared,
    1864             :  but no new one instituted.
    1865             : 
    1866             :  */
    1867             : 
    1868         648 : void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
    1869             : 
    1870             : {
    1871         648 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
    1872             : 
    1873             : #ifdef OGRAPISPY_ENABLED
    1874         648 :     if (bOGRAPISpyEnabled)
    1875           4 :         OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
    1876             : #endif
    1877             : 
    1878        1296 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
    1879         648 :         OGRGeometry::FromHandle(hGeom));
    1880             : }
    1881             : 
    1882             : /************************************************************************/
    1883             : /*                      OGR_L_SetSpatialFilterEx()                      */
    1884             : /************************************************************************/
    1885             : 
    1886             : /**
    1887             :  \brief Set a new spatial filter.
    1888             : 
    1889             :  This function set the geometry to be used as a spatial filter when
    1890             :  fetching features via the OGR_L_GetNextFeature() function.  Only
    1891             :  features that geometrically intersect the filter geometry will be
    1892             :  returned.
    1893             : 
    1894             :  Currently this test is may be inaccurately implemented, but it is
    1895             :  guaranteed that all features who's envelope (as returned by
    1896             :  OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
    1897             :  will be returned.  This can result in more shapes being returned that
    1898             :  should strictly be the case.
    1899             : 
    1900             :  This function makes an internal copy of the passed geometry.  The
    1901             :  passed geometry remains the responsibility of the caller, and may
    1902             :  be safely destroyed.
    1903             : 
    1904             :  For the time being the passed filter geometry should be in the same
    1905             :  SRS as the geometry field definition it corresponds to (as returned by
    1906             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
    1907             :  future this may be generalized.
    1908             : 
    1909             :  Note that only the last spatial filter set is applied, even if several
    1910             :  successive calls are done with different iGeomField values.
    1911             : 
    1912             :  This function is the same as the C++ method OGRLayer::SetSpatialFilter.
    1913             : 
    1914             :  @param hLayer handle to the layer on which to set the spatial filter.
    1915             :  @param iGeomField index of the geometry field on which the spatial filter
    1916             :  operates.
    1917             :  @param hGeom handle to the geometry to use as a filtering region.  NULL may
    1918             :  be passed indicating that the current spatial filter should be cleared,
    1919             :  but no new one instituted.
    1920             : 
    1921             :  @since GDAL 1.11
    1922             : 
    1923             :  */
    1924             : 
    1925          12 : void OGR_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
    1926             :                               OGRGeometryH hGeom)
    1927             : 
    1928             : {
    1929          12 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterEx");
    1930             : 
    1931             : #ifdef OGRAPISPY_ENABLED
    1932          12 :     if (bOGRAPISpyEnabled)
    1933           2 :         OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
    1934             : #endif
    1935             : 
    1936          24 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
    1937          12 :         iGeomField, OGRGeometry::FromHandle(hGeom));
    1938             : }
    1939             : 
    1940             : /************************************************************************/
    1941             : /*                        SetSpatialFilterRect()                        */
    1942             : /************************************************************************/
    1943             : 
    1944             : /**
    1945             :  \brief Set a new rectangular spatial filter.
    1946             : 
    1947             :  This method set rectangle to be used as a spatial filter when
    1948             :  fetching features via the GetNextFeature() method.  Only features that
    1949             :  geometrically intersect the given rectangle will be returned.
    1950             : 
    1951             :  The x/y values should be in the same coordinate system as the layer as
    1952             :  a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
    1953             :  method is normally implemented as creating a 5 vertex closed rectangular
    1954             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    1955             :  a convenience.
    1956             : 
    1957             :  The only way to clear a spatial filter set with this method is to
    1958             :  call OGRLayer::SetSpatialFilter(NULL).
    1959             : 
    1960             :  This method is the same as the C function OGR_L_SetSpatialFilterRect().
    1961             : 
    1962             :  @param dfMinX the minimum X coordinate for the rectangular region.
    1963             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    1964             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    1965             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    1966             : 
    1967             :  */
    1968             : 
    1969       48040 : OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
    1970             :                                       double dfMaxX, double dfMaxY)
    1971             : 
    1972             : {
    1973       48040 :     return SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
    1974             : }
    1975             : 
    1976             : /**
    1977             :  \brief Set a new rectangular spatial filter.
    1978             : 
    1979             :  This method set rectangle to be used as a spatial filter when
    1980             :  fetching features via the GetNextFeature() method.  Only features that
    1981             :  geometrically intersect the given rectangle will be returned.
    1982             : 
    1983             :  The x/y values should be in the same coordinate system as as the geometry
    1984             :  field definition it corresponds to (as returned by
    1985             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
    1986             :  method is normally implemented as creating a 5 vertex closed rectangular
    1987             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    1988             :  a convenience.
    1989             : 
    1990             :  The only way to clear a spatial filter set with this method is to
    1991             :  call OGRLayer::SetSpatialFilter(NULL).
    1992             : 
    1993             :  This method is the same as the C function OGR_L_SetSpatialFilterRectEx().
    1994             : 
    1995             :  @param iGeomField index of the geometry field on which the spatial filter
    1996             :  operates.
    1997             :  @param dfMinX the minimum X coordinate for the rectangular region.
    1998             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    1999             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    2000             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    2001             : 
    2002             :  @since GDAL 1.11
    2003             :  */
    2004             : 
    2005       48094 : OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
    2006             :                                       double dfMinY, double dfMaxX,
    2007             :                                       double dfMaxY)
    2008             : 
    2009             : {
    2010       96188 :     auto poRing = std::make_unique<OGRLinearRing>();
    2011       96188 :     OGRPolygon oPoly;
    2012             : 
    2013       48094 :     poRing->addPoint(dfMinX, dfMinY);
    2014       48094 :     poRing->addPoint(dfMinX, dfMaxY);
    2015       48094 :     poRing->addPoint(dfMaxX, dfMaxY);
    2016       48094 :     poRing->addPoint(dfMaxX, dfMinY);
    2017       48094 :     poRing->addPoint(dfMinX, dfMinY);
    2018             : 
    2019       48094 :     oPoly.addRing(std::move(poRing));
    2020             : 
    2021       96188 :     return SetSpatialFilter(iGeomField, &oPoly);
    2022             : }
    2023             : 
    2024             : /************************************************************************/
    2025             : /*                     OGR_L_SetSpatialFilterRect()                     */
    2026             : /************************************************************************/
    2027             : 
    2028             : /**
    2029             :  \brief Set a new rectangular spatial filter.
    2030             : 
    2031             :  This method set rectangle to be used as a spatial filter when
    2032             :  fetching features via the OGR_L_GetNextFeature() method.  Only features that
    2033             :  geometrically intersect the given rectangle will be returned.
    2034             : 
    2035             :  The x/y values should be in the same coordinate system as the layer as
    2036             :  a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
    2037             :  method is normally implemented as creating a 5 vertex closed rectangular
    2038             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    2039             :  a convenience.
    2040             : 
    2041             :  The only way to clear a spatial filter set with this method is to
    2042             :  call OGRLayer::SetSpatialFilter(NULL).
    2043             : 
    2044             :  This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
    2045             : 
    2046             :  @param hLayer handle to the layer on which to set the spatial filter.
    2047             :  @param dfMinX the minimum X coordinate for the rectangular region.
    2048             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    2049             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    2050             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    2051             : 
    2052             :  */
    2053             : 
    2054       47752 : void OGR_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX, double dfMinY,
    2055             :                                 double dfMaxX, double dfMaxY)
    2056             : 
    2057             : {
    2058       47752 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRect");
    2059             : 
    2060             : #ifdef OGRAPISPY_ENABLED
    2061       47752 :     if (bOGRAPISpyEnabled)
    2062           2 :         OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX,
    2063             :                                          dfMaxY);
    2064             : #endif
    2065             : 
    2066       47752 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX,
    2067             :                                                        dfMaxY);
    2068             : }
    2069             : 
    2070             : /************************************************************************/
    2071             : /*                    OGR_L_SetSpatialFilterRectEx()                    */
    2072             : /************************************************************************/
    2073             : 
    2074             : /**
    2075             :  \brief Set a new rectangular spatial filter.
    2076             : 
    2077             :  This method set rectangle to be used as a spatial filter when
    2078             :  fetching features via the OGR_L_GetNextFeature() method.  Only features that
    2079             :  geometrically intersect the given rectangle will be returned.
    2080             : 
    2081             :  The x/y values should be in the same coordinate system as as the geometry
    2082             :  field definition it corresponds to (as returned by
    2083             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
    2084             :  method is normally implemented as creating a 5 vertex closed rectangular
    2085             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    2086             :  a convenience.
    2087             : 
    2088             :  The only way to clear a spatial filter set with this method is to
    2089             :  call OGRLayer::SetSpatialFilter(NULL).
    2090             : 
    2091             :  This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
    2092             : 
    2093             :  @param hLayer handle to the layer on which to set the spatial filter.
    2094             :  @param iGeomField index of the geometry field on which the spatial filter
    2095             :  operates.
    2096             :  @param dfMinX the minimum X coordinate for the rectangular region.
    2097             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    2098             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    2099             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    2100             : 
    2101             :  @since GDAL 1.11
    2102             :  */
    2103             : 
    2104          15 : void OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
    2105             :                                   double dfMinX, double dfMinY, double dfMaxX,
    2106             :                                   double dfMaxY)
    2107             : 
    2108             : {
    2109          15 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRectEx");
    2110             : 
    2111             : #ifdef OGRAPISPY_ENABLED
    2112          15 :     if (bOGRAPISpyEnabled)
    2113           2 :         OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY,
    2114             :                                            dfMaxX, dfMaxY);
    2115             : #endif
    2116             : 
    2117          15 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(iGeomField, dfMinX,
    2118             :                                                        dfMinY, dfMaxX, dfMaxY);
    2119             : }
    2120             : 
    2121             : /************************************************************************/
    2122             : /*                           InstallFilter()                            */
    2123             : /*                                                                      */
    2124             : /*      This method is only intended to be used from within             */
    2125             : /*      drivers, normally from the SetSpatialFilter() method.           */
    2126             : /*      It installs a filter, and also tests it to see if it is         */
    2127             : /*      rectangular.  If so, it this is kept track of alongside the     */
    2128             : /*      filter geometry itself so we can do cheaper comparisons in      */
    2129             : /*      the FilterGeometry() call.                                      */
    2130             : /*                                                                      */
    2131             : /*      Returns TRUE if the newly installed filter differs in some      */
    2132             : /*      way from the current one.                                       */
    2133             : /************************************************************************/
    2134             : 
    2135             : //! @cond Doxygen_Suppress
    2136       64152 : int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
    2137             : 
    2138             : {
    2139       64152 :     if (m_poFilterGeom == poFilter)
    2140       10221 :         return FALSE;
    2141             : 
    2142             :     /* -------------------------------------------------------------------- */
    2143             :     /*      Replace the existing filter.                                    */
    2144             :     /* -------------------------------------------------------------------- */
    2145       53931 :     if (m_poFilterGeom != nullptr)
    2146             :     {
    2147       51065 :         delete m_poFilterGeom;
    2148       51065 :         m_poFilterGeom = nullptr;
    2149             :     }
    2150             : 
    2151       53931 :     if (m_pPreparedFilterGeom != nullptr)
    2152             :     {
    2153       51065 :         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
    2154       51065 :         m_pPreparedFilterGeom = nullptr;
    2155             :     }
    2156             : 
    2157       53931 :     if (poFilter != nullptr)
    2158       51929 :         m_poFilterGeom = poFilter->clone();
    2159             : 
    2160       53931 :     m_bFilterIsEnvelope = FALSE;
    2161             : 
    2162       53931 :     if (m_poFilterGeom == nullptr)
    2163        2002 :         return TRUE;
    2164             : 
    2165       51929 :     m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
    2166             : 
    2167             :     /* Compile geometry filter as a prepared geometry */
    2168       51929 :     m_pPreparedFilterGeom =
    2169       51929 :         OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
    2170             : 
    2171       51929 :     m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
    2172             : 
    2173       51929 :     return TRUE;
    2174             : }
    2175             : 
    2176             : //! @endcond
    2177             : 
    2178             : /************************************************************************/
    2179             : /*                   DoesGeometryHavePointInEnvelope()                  */
    2180             : /************************************************************************/
    2181             : 
    2182        5215 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
    2183             :                                             const OGREnvelope &sEnvelope)
    2184             : {
    2185        5215 :     const OGRLineString *poLS = nullptr;
    2186             : 
    2187        5215 :     switch (wkbFlatten(poGeometry->getGeometryType()))
    2188             :     {
    2189          36 :         case wkbPoint:
    2190             :         {
    2191          36 :             const auto poPoint = poGeometry->toPoint();
    2192          36 :             const double x = poPoint->getX();
    2193          36 :             const double y = poPoint->getY();
    2194          31 :             return (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
    2195          67 :                     x <= sEnvelope.MaxX && y <= sEnvelope.MaxY);
    2196             :         }
    2197             : 
    2198         394 :         case wkbLineString:
    2199         394 :             poLS = poGeometry->toLineString();
    2200         394 :             break;
    2201             : 
    2202        4083 :         case wkbPolygon:
    2203             :         {
    2204        4083 :             const OGRPolygon *poPoly = poGeometry->toPolygon();
    2205        4083 :             poLS = poPoly->getExteriorRing();
    2206        4083 :             break;
    2207             :         }
    2208             : 
    2209         461 :         case wkbMultiPoint:
    2210             :         case wkbMultiLineString:
    2211             :         case wkbMultiPolygon:
    2212             :         case wkbGeometryCollection:
    2213             :         {
    2214         693 :             for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
    2215             :             {
    2216         607 :                 if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
    2217         375 :                     return true;
    2218             :             }
    2219          86 :             return false;
    2220             :         }
    2221             : 
    2222         241 :         default:
    2223         241 :             return false;
    2224             :     }
    2225             : 
    2226        4477 :     if (poLS != nullptr)
    2227             :     {
    2228        4477 :         const int nNumPoints = poLS->getNumPoints();
    2229       52142 :         for (int i = 0; i < nNumPoints; i++)
    2230             :         {
    2231       51129 :             const double x = poLS->getX(i);
    2232       51129 :             const double y = poLS->getY(i);
    2233       51129 :             if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
    2234       20319 :                 x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
    2235             :             {
    2236        3464 :                 return true;
    2237             :             }
    2238             :         }
    2239             :     }
    2240             : 
    2241        1013 :     return false;
    2242             : }
    2243             : 
    2244             : /************************************************************************/
    2245             : /*                           FilterGeometry()                           */
    2246             : /*                                                                      */
    2247             : /*      Compare the passed in geometry to the currently installed       */
    2248             : /*      filter.  Optimize for case where filter is just an              */
    2249             : /*      envelope.                                                       */
    2250             : /************************************************************************/
    2251             : 
    2252             : //! @cond Doxygen_Suppress
    2253      454049 : int OGRLayer::FilterGeometry(const OGRGeometry *poGeometry)
    2254             : 
    2255             : {
    2256             :     /* -------------------------------------------------------------------- */
    2257             :     /*      In trivial cases of new filter or target geometry, we accept    */
    2258             :     /*      an intersection.  No geometry is taken to mean "the whole       */
    2259             :     /*      world".                                                         */
    2260             :     /* -------------------------------------------------------------------- */
    2261      454049 :     if (m_poFilterGeom == nullptr)
    2262         376 :         return TRUE;
    2263             : 
    2264      453673 :     if (poGeometry == nullptr || poGeometry->IsEmpty())
    2265         303 :         return FALSE;
    2266             : 
    2267             :     /* -------------------------------------------------------------------- */
    2268             :     /*      Compute the target geometry envelope, and if there is no        */
    2269             :     /*      intersection between the envelopes we are sure not to have      */
    2270             :     /*      any intersection.                                               */
    2271             :     /* -------------------------------------------------------------------- */
    2272      453370 :     OGREnvelope sGeomEnv;
    2273             : 
    2274      453370 :     poGeometry->getEnvelope(&sGeomEnv);
    2275             : 
    2276      453370 :     if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
    2277      299596 :         sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
    2278      231273 :         m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
    2279      130621 :         m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
    2280      339165 :         return FALSE;
    2281             : 
    2282             :     /* -------------------------------------------------------------------- */
    2283             :     /*      If the filter geometry is its own envelope and if the           */
    2284             :     /*      envelope of the geometry is inside the filter geometry,         */
    2285             :     /*      the geometry itself is inside the filter geometry               */
    2286             :     /* -------------------------------------------------------------------- */
    2287      114205 :     if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
    2288      110949 :         sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
    2289      109722 :         sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
    2290      108902 :         sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
    2291             :     {
    2292      108515 :         return TRUE;
    2293             :     }
    2294             :     else
    2295             :     {
    2296             :         // If the filter geometry is its own envelope and if the geometry has
    2297             :         // at least one point inside the filter geometry, the geometry itself
    2298             :         // intersects the filter geometry.
    2299        5690 :         if (m_bFilterIsEnvelope)
    2300             :         {
    2301        4608 :             if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
    2302        3474 :                 return true;
    2303             :         }
    2304             : 
    2305             :         /* --------------------------------------------------------------------
    2306             :          */
    2307             :         /*      Fallback to full intersect test (using GEOS) if we still */
    2308             :         /*      don't know for sure. */
    2309             :         /* --------------------------------------------------------------------
    2310             :          */
    2311        2216 :         if (OGRGeometryFactory::haveGEOS())
    2312             :         {
    2313             :             // CPLDebug("OGRLayer", "GEOS intersection");
    2314        2216 :             if (m_pPreparedFilterGeom != nullptr)
    2315        2216 :                 return OGRPreparedGeometryIntersects(
    2316             :                     m_pPreparedFilterGeom,
    2317             :                     OGRGeometry::ToHandle(
    2318        2216 :                         const_cast<OGRGeometry *>(poGeometry)));
    2319             :             else
    2320           0 :                 return m_poFilterGeom->Intersects(poGeometry);
    2321             :         }
    2322             :         else
    2323           0 :             return TRUE;
    2324             :     }
    2325             : }
    2326             : 
    2327             : /************************************************************************/
    2328             : /*                         FilterWKBGeometry()                          */
    2329             : /************************************************************************/
    2330             : 
    2331         230 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
    2332             :                                  bool bEnvelopeAlreadySet,
    2333             :                                  OGREnvelope &sEnvelope) const
    2334             : {
    2335         230 :     OGRPreparedGeometry *pPreparedFilterGeom = m_pPreparedFilterGeom;
    2336         460 :     bool bRet = FilterWKBGeometry(
    2337         230 :         pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope, m_poFilterGeom,
    2338         230 :         m_bFilterIsEnvelope, m_sFilterEnvelope, pPreparedFilterGeom);
    2339         230 :     const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
    2340         230 :     return bRet;
    2341             : }
    2342             : 
    2343             : /* static */
    2344         334 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
    2345             :                                  bool bEnvelopeAlreadySet,
    2346             :                                  OGREnvelope &sEnvelope,
    2347             :                                  const OGRGeometry *poFilterGeom,
    2348             :                                  bool bFilterIsEnvelope,
    2349             :                                  const OGREnvelope &sFilterEnvelope,
    2350             :                                  OGRPreparedGeometry *&pPreparedFilterGeom)
    2351             : {
    2352         334 :     if (!poFilterGeom)
    2353           0 :         return true;
    2354             : 
    2355         637 :     if ((bEnvelopeAlreadySet ||
    2356         668 :          OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
    2357         334 :         sFilterEnvelope.Intersects(sEnvelope))
    2358             :     {
    2359         161 :         if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
    2360             :         {
    2361          98 :             return true;
    2362             :         }
    2363             :         else
    2364             :         {
    2365         126 :             if (bFilterIsEnvelope &&
    2366          63 :                 OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
    2367             :             {
    2368          51 :                 return true;
    2369             :             }
    2370          12 :             else if (OGRGeometryFactory::haveGEOS())
    2371             :             {
    2372          12 :                 OGRGeometry *poGeom = nullptr;
    2373          12 :                 int ret = FALSE;
    2374          12 :                 if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
    2375          12 :                                                       nWKBSize) == OGRERR_NONE)
    2376             :                 {
    2377          12 :                     if (!pPreparedFilterGeom)
    2378             :                     {
    2379           0 :                         pPreparedFilterGeom =
    2380           0 :                             OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
    2381             :                                 const_cast<OGRGeometry *>(poFilterGeom)));
    2382             :                     }
    2383          12 :                     if (pPreparedFilterGeom)
    2384          12 :                         ret = OGRPreparedGeometryIntersects(
    2385             :                             pPreparedFilterGeom,
    2386             :                             OGRGeometry::ToHandle(
    2387             :                                 const_cast<OGRGeometry *>(poGeom)));
    2388             :                     else
    2389           0 :                         ret = poFilterGeom->Intersects(poGeom);
    2390             :                 }
    2391          12 :                 delete poGeom;
    2392          12 :                 return CPL_TO_BOOL(ret);
    2393             :             }
    2394             :             else
    2395             :             {
    2396             :                 // Assume intersection
    2397           0 :                 return true;
    2398             :             }
    2399             :         }
    2400             :     }
    2401             : 
    2402         173 :     return false;
    2403             : }
    2404             : 
    2405             : /************************************************************************/
    2406             : /*                          PrepareStartTransaction()                   */
    2407             : /************************************************************************/
    2408             : 
    2409        3330 : void OGRLayer::PrepareStartTransaction()
    2410             : {
    2411        3330 :     m_apoFieldDefnChanges.clear();
    2412        3330 :     m_apoGeomFieldDefnChanges.clear();
    2413        3330 : }
    2414             : 
    2415             : /************************************************************************/
    2416             : /*                          FinishRollbackTransaction()                 */
    2417             : /************************************************************************/
    2418             : 
    2419         171 : void OGRLayer::FinishRollbackTransaction(const std::string &osSavepointName)
    2420             : {
    2421             : 
    2422             :     // Deleted fields can be safely removed from the storage after being restored.
    2423         342 :     std::vector<int> toBeRemoved;
    2424             : 
    2425         171 :     bool bSavepointFound = false;
    2426             : 
    2427             :     // Loop through all changed fields and reset them to their previous state.
    2428         374 :     for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
    2429             :          i--)
    2430             :     {
    2431         203 :         auto &oFieldChange = m_apoFieldDefnChanges[i];
    2432             : 
    2433         203 :         if (!osSavepointName.empty())
    2434             :         {
    2435         172 :             if (oFieldChange.osSavepointName == osSavepointName)
    2436             :             {
    2437          60 :                 bSavepointFound = true;
    2438             :             }
    2439         112 :             else if (bSavepointFound)
    2440             :             {
    2441          56 :                 continue;
    2442             :             }
    2443             :         }
    2444             : 
    2445         147 :         CPLAssert(oFieldChange.poFieldDefn);
    2446         147 :         const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
    2447         147 :         const int iField = oFieldChange.iField;
    2448         147 :         if (iField >= 0)
    2449             :         {
    2450         147 :             switch (oFieldChange.eChangeType)
    2451             :             {
    2452         128 :                 case FieldChangeType::DELETE_FIELD:
    2453             :                 {
    2454             :                     // Transfer ownership of the field to the layer
    2455         256 :                     whileUnsealing(GetLayerDefn())
    2456         128 :                         ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
    2457             : 
    2458             :                     // Now move the field to the right place
    2459             :                     // from the last position to its original position
    2460         128 :                     const int iFieldCount = GetLayerDefn()->GetFieldCount();
    2461         128 :                     CPLAssert(iFieldCount > 0);
    2462         128 :                     CPLAssert(iFieldCount > iField);
    2463         256 :                     std::vector<int> anOrder(iFieldCount);
    2464         204 :                     for (int j = 0; j < iField; j++)
    2465             :                     {
    2466          76 :                         anOrder[j] = j;
    2467             :                     }
    2468         248 :                     for (int j = iField + 1; j < iFieldCount; j++)
    2469             :                     {
    2470         120 :                         anOrder[j] = j - 1;
    2471             :                     }
    2472         128 :                     anOrder[iField] = iFieldCount - 1;
    2473         256 :                     if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
    2474         128 :                                            ->ReorderFieldDefns(anOrder.data()))
    2475             :                     {
    2476         128 :                         toBeRemoved.push_back(i);
    2477             :                     }
    2478             :                     else
    2479             :                     {
    2480           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    2481             :                                  "Failed to restore deleted field %s", pszName);
    2482             :                     }
    2483         128 :                     break;
    2484             :                 }
    2485           8 :                 case FieldChangeType::ALTER_FIELD:
    2486             :                 {
    2487             :                     OGRFieldDefn *poFieldDefn =
    2488           8 :                         GetLayerDefn()->GetFieldDefn(iField);
    2489           8 :                     if (poFieldDefn)
    2490             :                     {
    2491           8 :                         *poFieldDefn = *oFieldChange.poFieldDefn;
    2492           8 :                         toBeRemoved.push_back(i);
    2493             :                     }
    2494             :                     else
    2495             :                     {
    2496           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    2497             :                                  "Failed to restore altered field %s", pszName);
    2498             :                     }
    2499           8 :                     break;
    2500             :                 }
    2501          11 :                 case FieldChangeType::ADD_FIELD:
    2502             :                 {
    2503             :                     std::unique_ptr<OGRFieldDefn> poFieldDef =
    2504          22 :                         GetLayerDefn()->StealFieldDefn(iField);
    2505          11 :                     if (poFieldDef)
    2506             :                     {
    2507          11 :                         oFieldChange.poFieldDefn = std::move(poFieldDef);
    2508             :                     }
    2509             :                     else
    2510             :                     {
    2511           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    2512             :                                  "Failed to delete added field %s", pszName);
    2513             :                     }
    2514          11 :                     break;
    2515             :                 }
    2516             :             }
    2517             :         }
    2518             :         else
    2519             :         {
    2520           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2521             :                      "Failed to restore field %s (field not found at index %d)",
    2522             :                      pszName, iField);
    2523             :         }
    2524             :     }
    2525             : 
    2526             :     // Remove from the storage the deleted fields that have been restored
    2527         307 :     for (const auto &i : toBeRemoved)
    2528             :     {
    2529         136 :         m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
    2530             :     }
    2531             : 
    2532             :     /**********************************************************************/
    2533             :     /* Reset geometry fields to their previous state.                    */
    2534             :     /**********************************************************************/
    2535             : 
    2536         171 :     bSavepointFound = false;
    2537             : 
    2538             :     // Loop through all changed geometry fields and reset them to their previous state.
    2539         171 :     for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
    2540             :          i--)
    2541             :     {
    2542           0 :         auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
    2543             : 
    2544           0 :         if (!osSavepointName.empty())
    2545             :         {
    2546           0 :             if (oGeomFieldChange.osSavepointName == osSavepointName)
    2547             :             {
    2548           0 :                 bSavepointFound = true;
    2549             :             }
    2550           0 :             else if (bSavepointFound)
    2551             :             {
    2552           0 :                 continue;
    2553             :             }
    2554             :         }
    2555           0 :         const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
    2556           0 :         const int iGeomField = oGeomFieldChange.iField;
    2557           0 :         if (iGeomField >= 0)
    2558             :         {
    2559           0 :             switch (oGeomFieldChange.eChangeType)
    2560             :             {
    2561           0 :                 case FieldChangeType::DELETE_FIELD:
    2562             :                 case FieldChangeType::ALTER_FIELD:
    2563             :                 {
    2564             :                     // Currently not handled by OGR for geometry fields
    2565           0 :                     break;
    2566             :                 }
    2567           0 :                 case FieldChangeType::ADD_FIELD:
    2568             :                 {
    2569             :                     std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
    2570           0 :                         GetLayerDefn()->StealGeomFieldDefn(
    2571           0 :                             oGeomFieldChange.iField);
    2572           0 :                     if (poGeomFieldDef)
    2573             :                     {
    2574             :                         oGeomFieldChange.poFieldDefn =
    2575           0 :                             std::move(poGeomFieldDef);
    2576             :                     }
    2577             :                     else
    2578             :                     {
    2579           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    2580             :                                  "Failed to delete added geometry field %s",
    2581             :                                  pszName);
    2582             :                     }
    2583           0 :                     break;
    2584             :                 }
    2585             :             }
    2586             :         }
    2587             :         else
    2588             :         {
    2589           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2590             :                      "Failed to restore geometry field %s (field not found at "
    2591             :                      "index %d)",
    2592             :                      pszName, oGeomFieldChange.iField);
    2593             :         }
    2594             :     }
    2595         171 : }
    2596             : 
    2597             : //! @endcond
    2598             : 
    2599             : /************************************************************************/
    2600             : /*                         OGR_L_ResetReading()                         */
    2601             : /************************************************************************/
    2602             : 
    2603       17668 : void OGR_L_ResetReading(OGRLayerH hLayer)
    2604             : 
    2605             : {
    2606       17668 :     VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
    2607             : 
    2608             : #ifdef OGRAPISPY_ENABLED
    2609       17668 :     if (bOGRAPISpyEnabled)
    2610           2 :         OGRAPISpy_L_ResetReading(hLayer);
    2611             : #endif
    2612             : 
    2613       17668 :     OGRLayer::FromHandle(hLayer)->ResetReading();
    2614             : }
    2615             : 
    2616             : /************************************************************************/
    2617             : /*                       InitializeIndexSupport()                       */
    2618             : /*                                                                      */
    2619             : /*      This is only intended to be called by driver layer              */
    2620             : /*      implementations but we don't make it protected so that the      */
    2621             : /*      datasources can do it too if that is more appropriate.          */
    2622             : /************************************************************************/
    2623             : 
    2624             : //! @cond Doxygen_Suppress
    2625             : OGRErr
    2626         650 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
    2627             : 
    2628             : {
    2629             : #ifdef HAVE_MITAB
    2630             :     OGRErr eErr;
    2631             : 
    2632         650 :     if (m_poAttrIndex != nullptr)
    2633         484 :         return OGRERR_NONE;
    2634             : 
    2635         166 :     m_poAttrIndex = OGRCreateDefaultLayerIndex();
    2636             : 
    2637         166 :     eErr = m_poAttrIndex->Initialize(pszFilename, this);
    2638         166 :     if (eErr != OGRERR_NONE)
    2639             :     {
    2640           0 :         delete m_poAttrIndex;
    2641           0 :         m_poAttrIndex = nullptr;
    2642             :     }
    2643             : 
    2644         166 :     return eErr;
    2645             : #else
    2646             :     return OGRERR_FAILURE;
    2647             : #endif
    2648             : }
    2649             : 
    2650             : //! @endcond
    2651             : 
    2652             : /************************************************************************/
    2653             : /*                             SyncToDisk()                             */
    2654             : /************************************************************************/
    2655             : 
    2656        4846 : OGRErr OGRLayer::SyncToDisk()
    2657             : 
    2658             : {
    2659        4846 :     return OGRERR_NONE;
    2660             : }
    2661             : 
    2662             : /************************************************************************/
    2663             : /*                          OGR_L_SyncToDisk()                          */
    2664             : /************************************************************************/
    2665             : 
    2666         251 : OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
    2667             : 
    2668             : {
    2669         251 :     VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
    2670             : 
    2671             : #ifdef OGRAPISPY_ENABLED
    2672         251 :     if (bOGRAPISpyEnabled)
    2673           2 :         OGRAPISpy_L_SyncToDisk(hLayer);
    2674             : #endif
    2675             : 
    2676         251 :     return OGRLayer::FromHandle(hLayer)->SyncToDisk();
    2677             : }
    2678             : 
    2679             : /************************************************************************/
    2680             : /*                           DeleteFeature()                            */
    2681             : /************************************************************************/
    2682             : 
    2683         320 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
    2684             : {
    2685         320 :     return OGRERR_UNSUPPORTED_OPERATION;
    2686             : }
    2687             : 
    2688             : /************************************************************************/
    2689             : /*                        OGR_L_DeleteFeature()                         */
    2690             : /************************************************************************/
    2691             : 
    2692        3355 : OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
    2693             : 
    2694             : {
    2695        3355 :     VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
    2696             : 
    2697             : #ifdef OGRAPISPY_ENABLED
    2698        3355 :     if (bOGRAPISpyEnabled)
    2699           2 :         OGRAPISpy_L_DeleteFeature(hLayer, nFID);
    2700             : #endif
    2701             : 
    2702        3355 :     return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
    2703             : }
    2704             : 
    2705             : /************************************************************************/
    2706             : /*                          GetFeaturesRead()                           */
    2707             : /************************************************************************/
    2708             : 
    2709             : //! @cond Doxygen_Suppress
    2710           0 : GIntBig OGRLayer::GetFeaturesRead()
    2711             : 
    2712             : {
    2713           0 :     return m_nFeaturesRead;
    2714             : }
    2715             : 
    2716             : //! @endcond
    2717             : 
    2718             : /************************************************************************/
    2719             : /*                       OGR_L_GetFeaturesRead()                        */
    2720             : /************************************************************************/
    2721             : 
    2722           0 : GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
    2723             : 
    2724             : {
    2725           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
    2726             : 
    2727           0 :     return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
    2728             : }
    2729             : 
    2730             : /************************************************************************/
    2731             : /*                             GetFIDColumn                             */
    2732             : /************************************************************************/
    2733             : 
    2734        7515 : const char *OGRLayer::GetFIDColumn()
    2735             : 
    2736             : {
    2737        7515 :     return "";
    2738             : }
    2739             : 
    2740             : /************************************************************************/
    2741             : /*                         OGR_L_GetFIDColumn()                         */
    2742             : /************************************************************************/
    2743             : 
    2744         388 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
    2745             : 
    2746             : {
    2747         388 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
    2748             : 
    2749             : #ifdef OGRAPISPY_ENABLED
    2750         388 :     if (bOGRAPISpyEnabled)
    2751           2 :         OGRAPISpy_L_GetFIDColumn(hLayer);
    2752             : #endif
    2753             : 
    2754         388 :     return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
    2755             : }
    2756             : 
    2757             : /************************************************************************/
    2758             : /*                         GetGeometryColumn()                          */
    2759             : /************************************************************************/
    2760             : 
    2761        3459 : const char *OGRLayer::GetGeometryColumn()
    2762             : 
    2763             : {
    2764        3459 :     if (GetLayerDefn()->GetGeomFieldCount() > 0)
    2765        3379 :         return GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef();
    2766             :     else
    2767          80 :         return "";
    2768             : }
    2769             : 
    2770             : /************************************************************************/
    2771             : /*                      OGR_L_GetGeometryColumn()                       */
    2772             : /************************************************************************/
    2773             : 
    2774         691 : const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
    2775             : 
    2776             : {
    2777         691 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
    2778             : 
    2779             : #ifdef OGRAPISPY_ENABLED
    2780         691 :     if (bOGRAPISpyEnabled)
    2781           2 :         OGRAPISpy_L_GetGeometryColumn(hLayer);
    2782             : #endif
    2783             : 
    2784         691 :     return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
    2785             : }
    2786             : 
    2787             : /************************************************************************/
    2788             : /*                            GetStyleTable()                           */
    2789             : /************************************************************************/
    2790             : 
    2791         953 : OGRStyleTable *OGRLayer::GetStyleTable()
    2792             : {
    2793         953 :     return m_poStyleTable;
    2794             : }
    2795             : 
    2796             : /************************************************************************/
    2797             : /*                         SetStyleTableDirectly()                      */
    2798             : /************************************************************************/
    2799             : 
    2800           0 : void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
    2801             : {
    2802           0 :     if (m_poStyleTable)
    2803           0 :         delete m_poStyleTable;
    2804           0 :     m_poStyleTable = poStyleTable;
    2805           0 : }
    2806             : 
    2807             : /************************************************************************/
    2808             : /*                            SetStyleTable()                           */
    2809             : /************************************************************************/
    2810             : 
    2811         950 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
    2812             : {
    2813         950 :     if (m_poStyleTable)
    2814           0 :         delete m_poStyleTable;
    2815         950 :     if (poStyleTable)
    2816           1 :         m_poStyleTable = poStyleTable->Clone();
    2817         950 : }
    2818             : 
    2819             : /************************************************************************/
    2820             : /*                         OGR_L_GetStyleTable()                        */
    2821             : /************************************************************************/
    2822             : 
    2823           3 : OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
    2824             : 
    2825             : {
    2826           3 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
    2827             : 
    2828             :     return reinterpret_cast<OGRStyleTableH>(
    2829           3 :         OGRLayer::FromHandle(hLayer)->GetStyleTable());
    2830             : }
    2831             : 
    2832             : /************************************************************************/
    2833             : /*                         OGR_L_SetStyleTableDirectly()                */
    2834             : /************************************************************************/
    2835             : 
    2836           0 : void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
    2837             : 
    2838             : {
    2839           0 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
    2840             : 
    2841           0 :     OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
    2842           0 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    2843             : }
    2844             : 
    2845             : /************************************************************************/
    2846             : /*                         OGR_L_SetStyleTable()                        */
    2847             : /************************************************************************/
    2848             : 
    2849           1 : void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
    2850             : 
    2851             : {
    2852           1 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
    2853           1 :     VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
    2854             : 
    2855           1 :     OGRLayer::FromHandle(hLayer)->SetStyleTable(
    2856           1 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    2857             : }
    2858             : 
    2859             : /************************************************************************/
    2860             : /*                               GetName()                              */
    2861             : /************************************************************************/
    2862             : 
    2863     1122670 : const char *OGRLayer::GetName()
    2864             : 
    2865             : {
    2866     1122670 :     return GetLayerDefn()->GetName();
    2867             : }
    2868             : 
    2869             : /************************************************************************/
    2870             : /*                           OGR_L_GetName()                            */
    2871             : /************************************************************************/
    2872             : 
    2873        1384 : const char *OGR_L_GetName(OGRLayerH hLayer)
    2874             : 
    2875             : {
    2876        1384 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
    2877             : 
    2878             : #ifdef OGRAPISPY_ENABLED
    2879        1384 :     if (bOGRAPISpyEnabled)
    2880           2 :         OGRAPISpy_L_GetName(hLayer);
    2881             : #endif
    2882             : 
    2883        1384 :     return OGRLayer::FromHandle(hLayer)->GetName();
    2884             : }
    2885             : 
    2886             : /************************************************************************/
    2887             : /*                            GetGeomType()                             */
    2888             : /************************************************************************/
    2889             : 
    2890      217190 : OGRwkbGeometryType OGRLayer::GetGeomType()
    2891             : {
    2892      217190 :     OGRFeatureDefn *poLayerDefn = GetLayerDefn();
    2893      217190 :     if (poLayerDefn == nullptr)
    2894             :     {
    2895           0 :         CPLDebug("OGR", "GetLayerType() returns NULL !");
    2896           0 :         return wkbUnknown;
    2897             :     }
    2898      217190 :     return poLayerDefn->GetGeomType();
    2899             : }
    2900             : 
    2901             : /************************************************************************/
    2902             : /*                         OGR_L_GetGeomType()                          */
    2903             : /************************************************************************/
    2904             : 
    2905        1102 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
    2906             : 
    2907             : {
    2908        1102 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
    2909             : 
    2910             : #ifdef OGRAPISPY_ENABLED
    2911        1102 :     if (bOGRAPISpyEnabled)
    2912           2 :         OGRAPISpy_L_GetGeomType(hLayer);
    2913             : #endif
    2914             : 
    2915        1102 :     OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
    2916        1102 :     if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
    2917             :     {
    2918           1 :         eType = OGR_GT_GetLinear(eType);
    2919             :     }
    2920        1102 :     return eType;
    2921             : }
    2922             : 
    2923             : /************************************************************************/
    2924             : /*                          SetIgnoredFields()                          */
    2925             : /************************************************************************/
    2926             : 
    2927        8403 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
    2928             : {
    2929        8403 :     OGRFeatureDefn *poDefn = GetLayerDefn();
    2930             : 
    2931             :     // first set everything as *not* ignored
    2932       63208 :     for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
    2933             :     {
    2934       54805 :         poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
    2935             :     }
    2936       19463 :     for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
    2937             :     {
    2938       11060 :         poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
    2939             :     }
    2940        8403 :     poDefn->SetStyleIgnored(FALSE);
    2941             : 
    2942             :     // ignore some fields
    2943       15882 :     for (const char *pszFieldName : cpl::Iterate(papszFields))
    2944             :     {
    2945             :         // check special fields
    2946        7479 :         if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
    2947         154 :             poDefn->SetGeometryIgnored(TRUE);
    2948        7325 :         else if (EQUAL(pszFieldName, "OGR_STYLE"))
    2949          13 :             poDefn->SetStyleIgnored(TRUE);
    2950             :         else
    2951             :         {
    2952             :             // check ordinary fields
    2953        7312 :             int iField = poDefn->GetFieldIndex(pszFieldName);
    2954        7312 :             if (iField == -1)
    2955             :             {
    2956             :                 // check geometry field
    2957        1638 :                 iField = poDefn->GetGeomFieldIndex(pszFieldName);
    2958        1638 :                 if (iField == -1)
    2959             :                 {
    2960           0 :                     return OGRERR_FAILURE;
    2961             :                 }
    2962             :                 else
    2963        1638 :                     poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
    2964             :             }
    2965             :             else
    2966        5674 :                 poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
    2967             :         }
    2968             :     }
    2969             : 
    2970        8403 :     return OGRERR_NONE;
    2971             : }
    2972             : 
    2973             : /************************************************************************/
    2974             : /*                       OGR_L_SetIgnoredFields()                       */
    2975             : /************************************************************************/
    2976             : 
    2977         265 : OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
    2978             : 
    2979             : {
    2980         265 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
    2981             : 
    2982             : #ifdef OGRAPISPY_ENABLED
    2983         265 :     if (bOGRAPISpyEnabled)
    2984           2 :         OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
    2985             : #endif
    2986             : 
    2987         265 :     return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
    2988             : }
    2989             : 
    2990             : /************************************************************************/
    2991             : /*                             Rename()                                 */
    2992             : /************************************************************************/
    2993             : 
    2994             : /** Rename layer.
    2995             :  *
    2996             :  * This operation is implemented only by layers that expose the OLCRename
    2997             :  * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
    2998             :  *
    2999             :  * This operation will fail if a layer with the new name already exists.
    3000             :  *
    3001             :  * On success, GetDescription() and GetLayerDefn()->GetName() will return
    3002             :  * pszNewName.
    3003             :  *
    3004             :  * Renaming the layer may interrupt current feature iteration.
    3005             :  *
    3006             :  * @param pszNewName New layer name. Must not be NULL.
    3007             :  * @return OGRERR_NONE in case of success
    3008             :  *
    3009             :  * @since GDAL 3.5
    3010             :  */
    3011           0 : OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
    3012             : {
    3013           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    3014             :              "Rename() not supported by this layer.");
    3015             : 
    3016           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    3017             : }
    3018             : 
    3019             : /************************************************************************/
    3020             : /*                           OGR_L_Rename()                             */
    3021             : /************************************************************************/
    3022             : 
    3023             : /** Rename layer.
    3024             :  *
    3025             :  * This operation is implemented only by layers that expose the OLCRename
    3026             :  * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
    3027             :  *
    3028             :  * This operation will fail if a layer with the new name already exists.
    3029             :  *
    3030             :  * On success, GetDescription() and GetLayerDefn()->GetName() will return
    3031             :  * pszNewName.
    3032             :  *
    3033             :  * Renaming the layer may interrupt current feature iteration.
    3034             :  *
    3035             :  * @param hLayer     Layer to rename.
    3036             :  * @param pszNewName New layer name. Must not be NULL.
    3037             :  * @return OGRERR_NONE in case of success
    3038             :  *
    3039             :  * @since GDAL 3.5
    3040             :  */
    3041          29 : OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
    3042             : 
    3043             : {
    3044          29 :     VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
    3045          29 :     VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
    3046             : 
    3047          29 :     return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
    3048             : }
    3049             : 
    3050             : /************************************************************************/
    3051             : /*         helper functions for layer overlay methods                   */
    3052             : /************************************************************************/
    3053             : 
    3054          50 : static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
    3055             : {
    3056          50 :     OGRErr ret = OGRERR_NONE;
    3057          50 :     OGRGeometry *g = pLayer->GetSpatialFilter();
    3058          50 :     *ppGeometry = g ? g->clone() : nullptr;
    3059          50 :     return ret;
    3060             : }
    3061             : 
    3062          69 : static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
    3063             : {
    3064          69 :     OGRErr ret = OGRERR_NONE;
    3065          69 :     int n = poDefn->GetFieldCount();
    3066          69 :     if (n > 0)
    3067             :     {
    3068          41 :         *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
    3069          41 :         if (!(*map))
    3070           0 :             return OGRERR_NOT_ENOUGH_MEMORY;
    3071         115 :         for (int i = 0; i < n; i++)
    3072          74 :             (*map)[i] = -1;
    3073             :     }
    3074          69 :     return ret;
    3075             : }
    3076             : 
    3077          39 : static OGRErr set_result_schema(OGRLayer *pLayerResult,
    3078             :                                 OGRFeatureDefn *poDefnInput,
    3079             :                                 OGRFeatureDefn *poDefnMethod, int *mapInput,
    3080             :                                 int *mapMethod, bool combined,
    3081             :                                 const char *const *papszOptions)
    3082             : {
    3083          39 :     OGRErr ret = OGRERR_NONE;
    3084          39 :     OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
    3085             :     const char *pszInputPrefix =
    3086          39 :         CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
    3087             :     const char *pszMethodPrefix =
    3088          39 :         CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
    3089             :     int bSkipFailures =
    3090          39 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    3091          39 :     if (poDefnResult->GetFieldCount() > 0)
    3092             :     {
    3093             :         // the user has defined the schema of the output layer
    3094           4 :         if (mapInput)
    3095             :         {
    3096           9 :             for (int iField = 0; iField < poDefnInput->GetFieldCount();
    3097             :                  iField++)
    3098             :             {
    3099             :                 CPLString osName(
    3100           5 :                     poDefnInput->GetFieldDefn(iField)->GetNameRef());
    3101           5 :                 if (pszInputPrefix != nullptr)
    3102           0 :                     osName = pszInputPrefix + osName;
    3103           5 :                 mapInput[iField] = poDefnResult->GetFieldIndex(osName);
    3104             :             }
    3105             :         }
    3106           4 :         if (!mapMethod)
    3107           2 :             return ret;
    3108             :         // cppcheck-suppress nullPointer
    3109           5 :         for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
    3110             :         {
    3111             :             // cppcheck-suppress nullPointer
    3112           3 :             CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
    3113           3 :             if (pszMethodPrefix != nullptr)
    3114           0 :                 osName = pszMethodPrefix + osName;
    3115           3 :             mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
    3116             :         }
    3117             :     }
    3118             :     else
    3119             :     {
    3120             :         // use schema from the input layer or from input and method layers
    3121          35 :         int nFieldsInput = poDefnInput->GetFieldCount();
    3122             : 
    3123             :         // If no prefix is specified and we have input+method layers, make
    3124             :         // sure we will generate unique field names
    3125          35 :         std::set<std::string> oSetInputFieldNames;
    3126          35 :         std::set<std::string> oSetMethodFieldNames;
    3127          35 :         if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
    3128             :             pszMethodPrefix == nullptr)
    3129             :         {
    3130          56 :             for (int iField = 0; iField < nFieldsInput; iField++)
    3131             :             {
    3132             :                 oSetInputFieldNames.insert(
    3133          28 :                     poDefnInput->GetFieldDefn(iField)->GetNameRef());
    3134             :             }
    3135          28 :             const int nFieldsMethod = poDefnMethod->GetFieldCount();
    3136          54 :             for (int iField = 0; iField < nFieldsMethod; iField++)
    3137             :             {
    3138             :                 oSetMethodFieldNames.insert(
    3139          26 :                     poDefnMethod->GetFieldDefn(iField)->GetNameRef());
    3140             :             }
    3141             :         }
    3142             : 
    3143          75 :         for (int iField = 0; iField < nFieldsInput; iField++)
    3144             :         {
    3145          40 :             OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
    3146          40 :             if (pszInputPrefix != nullptr)
    3147           0 :                 oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
    3148             :                                               oFieldDefn.GetNameRef()));
    3149          66 :             else if (!oSetMethodFieldNames.empty() &&
    3150          66 :                      oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
    3151          66 :                          oSetMethodFieldNames.end())
    3152             :             {
    3153             :                 // Field of same name present in method layer
    3154          17 :                 oFieldDefn.SetName(
    3155             :                     CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
    3156             :             }
    3157          40 :             ret = pLayerResult->CreateField(&oFieldDefn);
    3158          40 :             if (ret != OGRERR_NONE)
    3159             :             {
    3160           0 :                 if (!bSkipFailures)
    3161           0 :                     return ret;
    3162             :                 else
    3163             :                 {
    3164           0 :                     CPLErrorReset();
    3165           0 :                     ret = OGRERR_NONE;
    3166             :                 }
    3167             :             }
    3168          40 :             if (mapInput)
    3169          40 :                 mapInput[iField] = iField;
    3170             :         }
    3171          35 :         if (!combined)
    3172          11 :             return ret;
    3173          24 :         if (!mapMethod)
    3174          12 :             return ret;
    3175          12 :         if (!poDefnMethod)
    3176           0 :             return ret;
    3177          12 :         const int nFieldsMethod = poDefnMethod->GetFieldCount();
    3178          34 :         for (int iField = 0; iField < nFieldsMethod; iField++)
    3179             :         {
    3180          22 :             OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
    3181          22 :             if (pszMethodPrefix != nullptr)
    3182           0 :                 oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
    3183             :                                               oFieldDefn.GetNameRef()));
    3184          44 :             else if (!oSetInputFieldNames.empty() &&
    3185          44 :                      oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
    3186          44 :                          oSetInputFieldNames.end())
    3187             :             {
    3188             :                 // Field of same name present in method layer
    3189          15 :                 oFieldDefn.SetName(
    3190             :                     CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
    3191             :             }
    3192          22 :             ret = pLayerResult->CreateField(&oFieldDefn);
    3193          22 :             if (ret != OGRERR_NONE)
    3194             :             {
    3195           0 :                 if (!bSkipFailures)
    3196           0 :                     return ret;
    3197             :                 else
    3198             :                 {
    3199           0 :                     CPLErrorReset();
    3200           0 :                     ret = OGRERR_NONE;
    3201             :                 }
    3202             :             }
    3203          22 :             mapMethod[iField] = nFieldsInput + iField;
    3204             :         }
    3205             :     }
    3206          14 :     return ret;
    3207             : }
    3208             : 
    3209          91 : static OGRGeometry *set_filter_from(OGRLayer *pLayer,
    3210             :                                     OGRGeometry *pGeometryExistingFilter,
    3211             :                                     OGRFeature *pFeature)
    3212             : {
    3213          91 :     OGRGeometry *geom = pFeature->GetGeometryRef();
    3214          91 :     if (!geom)
    3215           0 :         return nullptr;
    3216          91 :     if (pGeometryExistingFilter)
    3217             :     {
    3218           0 :         if (!geom->Intersects(pGeometryExistingFilter))
    3219           0 :             return nullptr;
    3220           0 :         OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
    3221           0 :         if (intersection)
    3222             :         {
    3223           0 :             pLayer->SetSpatialFilter(intersection);
    3224           0 :             delete intersection;
    3225             :         }
    3226             :         else
    3227           0 :             return nullptr;
    3228             :     }
    3229             :     else
    3230             :     {
    3231          91 :         pLayer->SetSpatialFilter(geom);
    3232             :     }
    3233          91 :     return geom;
    3234             : }
    3235             : 
    3236          23 : static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
    3237             : {
    3238          23 :     OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    3239          23 :     if (eType == wkbPoint)
    3240           1 :         return OGRGeometryFactory::forceToMultiPoint(poGeom);
    3241          22 :     else if (eType == wkbPolygon)
    3242          22 :         return OGRGeometryFactory::forceToMultiPolygon(poGeom);
    3243           0 :     else if (eType == wkbLineString)
    3244           0 :         return OGRGeometryFactory::forceToMultiLineString(poGeom);
    3245             :     else
    3246           0 :         return poGeom;
    3247             : }
    3248             : 
    3249             : /************************************************************************/
    3250             : /*                          Intersection()                              */
    3251             : /************************************************************************/
    3252             : /**
    3253             :  * \brief Intersection of two layers.
    3254             :  *
    3255             :  * The result layer contains features whose geometries represent areas
    3256             :  * that are common between features in the input layer and in the
    3257             :  * method layer. The features in the result layer have attributes from
    3258             :  * both input and method layers. The schema of the result layer can be
    3259             :  * set by the user or, if it is empty, is initialized to contain all
    3260             :  * fields in the input and method layers.
    3261             :  *
    3262             :  * \note If the schema of the result is set by user and contains
    3263             :  * fields that have the same name as a field in input and in method
    3264             :  * layer, then the attribute in the result feature will get the value
    3265             :  * from the feature of the method layer.
    3266             :  *
    3267             :  * \note For best performance use the minimum amount of features in
    3268             :  * the method layer and copy it into a memory layer.
    3269             :  *
    3270             :  * \note This method relies on GEOS support. Do not use unless the
    3271             :  * GEOS support is compiled in.
    3272             :  *
    3273             :  * The recognized list of options is:
    3274             :  * <ul>
    3275             :  * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
    3276             :  *     feature could not be inserted or a GEOS call failed.
    3277             :  * </li>
    3278             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    3279             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    3280             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    3281             :  * </li>
    3282             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3283             :  *     will be created from the fields of the input layer.
    3284             :  * </li>
    3285             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3286             :  *     will be created from the fields of the method layer.
    3287             :  * </li>
    3288             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    3289             :  *     geometries to pretest intersection of features of method layer
    3290             :  *     with features of this layer.
    3291             :  * </li>
    3292             :  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
    3293             :  *     containment of features of method layer within the features of
    3294             :  *     this layer. This will speed up the method significantly in some
    3295             :  *     cases. Requires that the prepared geometries are in effect.
    3296             :  * </li>
    3297             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    3298             :  *     result features with lower dimension geometry that would
    3299             :  *     otherwise be added to the result layer. The default is YES, to add
    3300             :  *     features with lower dimension geometry, but only if the result layer
    3301             :  *     has an unknown geometry type.
    3302             :  * </li>
    3303             :  * </ul>
    3304             :  *
    3305             :  * This method is the same as the C function OGR_L_Intersection().
    3306             :  *
    3307             :  * @param pLayerMethod the method layer. Should not be NULL.
    3308             :  *
    3309             :  * @param pLayerResult the layer where the features resulting from the
    3310             :  * operation are inserted. Should not be NULL. See above the note
    3311             :  * about the schema.
    3312             :  *
    3313             :  * @param papszOptions NULL terminated list of options (may be NULL).
    3314             :  *
    3315             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    3316             :  * reporting progress or NULL.
    3317             :  *
    3318             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    3319             :  *
    3320             :  * @return an error code if there was an error or the execution was
    3321             :  * interrupted, OGRERR_NONE otherwise.
    3322             :  *
    3323             :  * @note The first geometry field is always used.
    3324             :  *
    3325             :  * @since OGR 1.10
    3326             :  */
    3327             : 
    3328           8 : OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    3329             :                               char **papszOptions, GDALProgressFunc pfnProgress,
    3330             :                               void *pProgressArg)
    3331             : {
    3332           8 :     OGRErr ret = OGRERR_NONE;
    3333           8 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    3334           8 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    3335           8 :     OGRFeatureDefn *poDefnResult = nullptr;
    3336           8 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    3337           8 :     int *mapInput = nullptr;
    3338           8 :     int *mapMethod = nullptr;
    3339           8 :     OGREnvelope sEnvelopeMethod;
    3340             :     GBool bEnvelopeSet;
    3341           8 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    3342           8 :     double progress_counter = 0;
    3343           8 :     double progress_ticker = 0;
    3344             :     const bool bSkipFailures =
    3345           8 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    3346           8 :     const bool bPromoteToMulti = CPLTestBool(
    3347             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    3348           8 :     const bool bUsePreparedGeometries = CPLTestBool(
    3349             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    3350           8 :     const bool bPretestContainment = CPLTestBool(
    3351             :         CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
    3352           8 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    3353             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    3354             : 
    3355             :     // check for GEOS
    3356           8 :     if (!OGRGeometryFactory::haveGEOS())
    3357             :     {
    3358           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3359             :                  "OGRLayer::Intersection() requires GEOS support");
    3360           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    3361             :     }
    3362             : 
    3363             :     // get resources
    3364           8 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    3365           8 :     if (ret != OGRERR_NONE)
    3366           0 :         goto done;
    3367           8 :     ret = create_field_map(poDefnInput, &mapInput);
    3368           8 :     if (ret != OGRERR_NONE)
    3369           0 :         goto done;
    3370           8 :     ret = create_field_map(poDefnMethod, &mapMethod);
    3371           8 :     if (ret != OGRERR_NONE)
    3372           0 :         goto done;
    3373           8 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    3374             :                             mapMethod, true, papszOptions);
    3375           8 :     if (ret != OGRERR_NONE)
    3376           0 :         goto done;
    3377           8 :     poDefnResult = pLayerResult->GetLayerDefn();
    3378           8 :     bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
    3379           8 :     if (bKeepLowerDimGeom)
    3380             :     {
    3381             :         // require that the result layer is of geom type unknown
    3382           6 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    3383             :         {
    3384           1 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    3385             :                             "since the result layer does not allow it.");
    3386           1 :             bKeepLowerDimGeom = false;
    3387             :         }
    3388             :     }
    3389             : 
    3390          22 :     for (auto &&x : this)
    3391             :     {
    3392             : 
    3393          14 :         if (pfnProgress)
    3394             :         {
    3395           3 :             double p = progress_counter / progress_max;
    3396           3 :             if (p > progress_ticker)
    3397             :             {
    3398           1 :                 if (!pfnProgress(p, "", pProgressArg))
    3399             :                 {
    3400           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3401           0 :                     ret = OGRERR_FAILURE;
    3402           0 :                     goto done;
    3403             :                 }
    3404             :             }
    3405           3 :             progress_counter += 1.0;
    3406             :         }
    3407             : 
    3408             :         // is it worth to proceed?
    3409          14 :         if (bEnvelopeSet)
    3410             :         {
    3411          14 :             OGRGeometry *x_geom = x->GetGeometryRef();
    3412          14 :             if (x_geom)
    3413             :             {
    3414          14 :                 OGREnvelope x_env;
    3415          14 :                 x_geom->getEnvelope(&x_env);
    3416          14 :                 if (x_env.MaxX < sEnvelopeMethod.MinX ||
    3417          14 :                     x_env.MaxY < sEnvelopeMethod.MinY ||
    3418          14 :                     sEnvelopeMethod.MaxX < x_env.MinX ||
    3419          14 :                     sEnvelopeMethod.MaxY < x_env.MinY)
    3420             :                 {
    3421           0 :                     continue;
    3422             :                 }
    3423             :             }
    3424             :             else
    3425             :             {
    3426           0 :                 continue;
    3427             :             }
    3428             :         }
    3429             : 
    3430             :         // set up the filter for method layer
    3431          14 :         CPLErrorReset();
    3432             :         OGRGeometry *x_geom =
    3433          14 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    3434          14 :         if (CPLGetLastErrorType() != CE_None)
    3435             :         {
    3436           0 :             if (!bSkipFailures)
    3437             :             {
    3438           0 :                 ret = OGRERR_FAILURE;
    3439           0 :                 goto done;
    3440             :             }
    3441             :             else
    3442             :             {
    3443           0 :                 CPLErrorReset();
    3444           0 :                 ret = OGRERR_NONE;
    3445             :             }
    3446             :         }
    3447          14 :         if (!x_geom)
    3448             :         {
    3449           0 :             continue;
    3450             :         }
    3451             : 
    3452           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    3453          14 :         if (bUsePreparedGeometries)
    3454             :         {
    3455          14 :             x_prepared_geom.reset(
    3456             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    3457          14 :             if (!x_prepared_geom)
    3458             :             {
    3459           0 :                 goto done;
    3460             :             }
    3461             :         }
    3462             : 
    3463          30 :         for (auto &&y : pLayerMethod)
    3464             :         {
    3465          16 :             OGRGeometry *y_geom = y->GetGeometryRef();
    3466          16 :             if (!y_geom)
    3467           4 :                 continue;
    3468           0 :             OGRGeometryUniquePtr z_geom;
    3469             : 
    3470          16 :             if (x_prepared_geom)
    3471             :             {
    3472          16 :                 CPLErrorReset();
    3473          16 :                 ret = OGRERR_NONE;
    3474          16 :                 if (bPretestContainment &&
    3475           0 :                     OGRPreparedGeometryContains(x_prepared_geom.get(),
    3476             :                                                 OGRGeometry::ToHandle(y_geom)))
    3477             :                 {
    3478           0 :                     if (CPLGetLastErrorType() == CE_None)
    3479           0 :                         z_geom.reset(y_geom->clone());
    3480             :                 }
    3481          16 :                 else if (!(OGRPreparedGeometryIntersects(
    3482             :                              x_prepared_geom.get(),
    3483             :                              OGRGeometry::ToHandle(y_geom))))
    3484             :                 {
    3485           0 :                     if (CPLGetLastErrorType() == CE_None)
    3486             :                     {
    3487           0 :                         continue;
    3488             :                     }
    3489             :                 }
    3490          16 :                 if (CPLGetLastErrorType() != CE_None)
    3491             :                 {
    3492           0 :                     if (!bSkipFailures)
    3493             :                     {
    3494           0 :                         ret = OGRERR_FAILURE;
    3495           0 :                         goto done;
    3496             :                     }
    3497             :                     else
    3498             :                     {
    3499           0 :                         CPLErrorReset();
    3500           0 :                         ret = OGRERR_NONE;
    3501           0 :                         continue;
    3502             :                     }
    3503             :                 }
    3504             :             }
    3505          16 :             if (!z_geom)
    3506             :             {
    3507          16 :                 CPLErrorReset();
    3508          16 :                 z_geom.reset(x_geom->Intersection(y_geom));
    3509          16 :                 if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
    3510             :                 {
    3511           0 :                     if (!bSkipFailures)
    3512             :                     {
    3513           0 :                         ret = OGRERR_FAILURE;
    3514           0 :                         goto done;
    3515             :                     }
    3516             :                     else
    3517             :                     {
    3518           0 :                         CPLErrorReset();
    3519           0 :                         ret = OGRERR_NONE;
    3520           0 :                         continue;
    3521             :                     }
    3522             :                 }
    3523          32 :                 if (z_geom->IsEmpty() ||
    3524          16 :                     (!bKeepLowerDimGeom &&
    3525           7 :                      (x_geom->getDimension() == y_geom->getDimension() &&
    3526           7 :                       z_geom->getDimension() < x_geom->getDimension())))
    3527             :                 {
    3528           4 :                     continue;
    3529             :                 }
    3530             :             }
    3531          12 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3532          12 :             z->SetFieldsFrom(x.get(), mapInput);
    3533          12 :             z->SetFieldsFrom(y.get(), mapMethod);
    3534          12 :             if (bPromoteToMulti)
    3535           3 :                 z_geom.reset(promote_to_multi(z_geom.release()));
    3536          12 :             z->SetGeometryDirectly(z_geom.release());
    3537          12 :             ret = pLayerResult->CreateFeature(z.get());
    3538             : 
    3539          12 :             if (ret != OGRERR_NONE)
    3540             :             {
    3541           0 :                 if (!bSkipFailures)
    3542             :                 {
    3543           0 :                     goto done;
    3544             :                 }
    3545             :                 else
    3546             :                 {
    3547           0 :                     CPLErrorReset();
    3548           0 :                     ret = OGRERR_NONE;
    3549             :                 }
    3550             :             }
    3551             :         }
    3552             :     }
    3553           8 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    3554             :     {
    3555           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3556           0 :         ret = OGRERR_FAILURE;
    3557           0 :         goto done;
    3558             :     }
    3559           8 : done:
    3560             :     // release resources
    3561           8 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    3562           8 :     if (pGeometryMethodFilter)
    3563           0 :         delete pGeometryMethodFilter;
    3564           8 :     if (mapInput)
    3565           4 :         VSIFree(mapInput);
    3566           8 :     if (mapMethod)
    3567           4 :         VSIFree(mapMethod);
    3568           8 :     return ret;
    3569             : }
    3570             : 
    3571             : /************************************************************************/
    3572             : /*                       OGR_L_Intersection()                           */
    3573             : /************************************************************************/
    3574             : /**
    3575             :  * \brief Intersection of two layers.
    3576             :  *
    3577             :  * The result layer contains features whose geometries represent areas
    3578             :  * that are common between features in the input layer and in the
    3579             :  * method layer. The features in the result layer have attributes from
    3580             :  * both input and method layers. The schema of the result layer can be
    3581             :  * set by the user or, if it is empty, is initialized to contain all
    3582             :  * fields in the input and method layers.
    3583             :  *
    3584             :  * \note If the schema of the result is set by user and contains
    3585             :  * fields that have the same name as a field in input and in method
    3586             :  * layer, then the attribute in the result feature will get the value
    3587             :  * from the feature of the method layer.
    3588             :  *
    3589             :  * \note For best performance use the minimum amount of features in
    3590             :  * the method layer and copy it into a memory layer.
    3591             :  *
    3592             :  * \note This method relies on GEOS support. Do not use unless the
    3593             :  * GEOS support is compiled in.
    3594             :  *
    3595             :  * The recognized list of options is :
    3596             :  * <ul>
    3597             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    3598             :  *     feature could not be inserted or a GEOS call failed.
    3599             :  * </li>
    3600             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    3601             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    3602             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    3603             :  * </li>
    3604             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3605             :  *     will be created from the fields of the input layer.
    3606             :  * </li>
    3607             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3608             :  *     will be created from the fields of the method layer.
    3609             :  * </li>
    3610             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    3611             :  *     geometries to pretest intersection of features of method layer
    3612             :  *     with features of this layer.
    3613             :  * </li>
    3614             :  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
    3615             :  *     containment of features of method layer within the features of
    3616             :  *     this layer. This will speed up the method significantly in some
    3617             :  *     cases. Requires that the prepared geometries are in effect.
    3618             :  * </li>
    3619             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    3620             :  *     result features with lower dimension geometry that would
    3621             :  *     otherwise be added to the result layer. The default is YES, to add
    3622             :  *     features with lower dimension geometry, but only if the result layer
    3623             :  *     has an unknown geometry type.
    3624             :  * </li>
    3625             :  * </ul>
    3626             :  *
    3627             :  * This function is the same as the C++ method OGRLayer::Intersection().
    3628             :  *
    3629             :  * @param pLayerInput the input layer. Should not be NULL.
    3630             :  *
    3631             :  * @param pLayerMethod the method layer. Should not be NULL.
    3632             :  *
    3633             :  * @param pLayerResult the layer where the features resulting from the
    3634             :  * operation are inserted. Should not be NULL. See above the note
    3635             :  * about the schema.
    3636             :  *
    3637             :  * @param papszOptions NULL terminated list of options (may be NULL).
    3638             :  *
    3639             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    3640             :  * reporting progress or NULL.
    3641             :  *
    3642             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    3643             :  *
    3644             :  * @return an error code if there was an error or the execution was
    3645             :  * interrupted, OGRERR_NONE otherwise.
    3646             :  *
    3647             :  * @note The first geometry field is always used.
    3648             :  *
    3649             :  * @since OGR 1.10
    3650             :  */
    3651             : 
    3652           8 : OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    3653             :                           OGRLayerH pLayerResult, char **papszOptions,
    3654             :                           GDALProgressFunc pfnProgress, void *pProgressArg)
    3655             : 
    3656             : {
    3657           8 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
    3658           8 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
    3659             :                       OGRERR_INVALID_HANDLE);
    3660           8 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
    3661             :                       OGRERR_INVALID_HANDLE);
    3662             : 
    3663             :     return OGRLayer::FromHandle(pLayerInput)
    3664           8 :         ->Intersection(OGRLayer::FromHandle(pLayerMethod),
    3665             :                        OGRLayer::FromHandle(pLayerResult), papszOptions,
    3666           8 :                        pfnProgress, pProgressArg);
    3667             : }
    3668             : 
    3669             : /************************************************************************/
    3670             : /*                              Union()                                 */
    3671             : /************************************************************************/
    3672             : 
    3673             : /**
    3674             :  * \brief Union of two layers.
    3675             :  *
    3676             :  * The result layer contains features whose geometries represent areas
    3677             :  * that are either in the input layer, in the method layer, or in
    3678             :  * both. The features in the result layer have attributes from both
    3679             :  * input and method layers. For features which represent areas that
    3680             :  * are only in the input or in the method layer the respective
    3681             :  * attributes have undefined values. The schema of the result layer
    3682             :  * can be set by the user or, if it is empty, is initialized to
    3683             :  * contain all fields in the input and method layers.
    3684             :  *
    3685             :  * \note If the schema of the result is set by user and contains
    3686             :  * fields that have the same name as a field in input and in method
    3687             :  * layer, then the attribute in the result feature will get the value
    3688             :  * from the feature of the method layer (even if it is undefined).
    3689             :  *
    3690             :  * \note For best performance use the minimum amount of features in
    3691             :  * the method layer and copy it into a memory layer.
    3692             :  *
    3693             :  * \note This method relies on GEOS support. Do not use unless the
    3694             :  * GEOS support is compiled in.
    3695             :  *
    3696             :  * The recognized list of options is :
    3697             :  * <ul>
    3698             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    3699             :  *     feature could not be inserted or a GEOS call failed.
    3700             :  * </li>
    3701             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    3702             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    3703             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    3704             :  * </li>
    3705             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3706             :  *     will be created from the fields of the input layer.
    3707             :  * </li>
    3708             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3709             :  *     will be created from the fields of the method layer.
    3710             :  * </li>
    3711             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    3712             :  *     geometries to pretest intersection of features of method layer
    3713             :  *     with features of this layer.
    3714             :  * </li>
    3715             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    3716             :  *     result features with lower dimension geometry that would
    3717             :  *     otherwise be added to the result layer. The default is YES, to add
    3718             :  *     features with lower dimension geometry, but only if the result layer
    3719             :  *     has an unknown geometry type.
    3720             :  * </li>
    3721             :  * </ul>
    3722             :  *
    3723             :  * This method is the same as the C function OGR_L_Union().
    3724             :  *
    3725             :  * @param pLayerMethod the method layer. Should not be NULL.
    3726             :  *
    3727             :  * @param pLayerResult the layer where the features resulting from the
    3728             :  * operation are inserted. Should not be NULL. See above the note
    3729             :  * about the schema.
    3730             :  *
    3731             :  * @param papszOptions NULL terminated list of options (may be NULL).
    3732             :  *
    3733             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    3734             :  * reporting progress or NULL.
    3735             :  *
    3736             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    3737             :  *
    3738             :  * @return an error code if there was an error or the execution was
    3739             :  * interrupted, OGRERR_NONE otherwise.
    3740             :  *
    3741             :  * @note The first geometry field is always used.
    3742             :  *
    3743             :  * @since OGR 1.10
    3744             :  */
    3745             : 
    3746           7 : OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    3747             :                        char **papszOptions, GDALProgressFunc pfnProgress,
    3748             :                        void *pProgressArg)
    3749             : {
    3750           7 :     OGRErr ret = OGRERR_NONE;
    3751           7 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    3752           7 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    3753           7 :     OGRFeatureDefn *poDefnResult = nullptr;
    3754           7 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    3755           7 :     OGRGeometry *pGeometryInputFilter = nullptr;
    3756           7 :     int *mapInput = nullptr;
    3757           7 :     int *mapMethod = nullptr;
    3758             :     double progress_max =
    3759           7 :         static_cast<double>(GetFeatureCount(FALSE)) +
    3760           7 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    3761           7 :     double progress_counter = 0;
    3762           7 :     double progress_ticker = 0;
    3763             :     const bool bSkipFailures =
    3764           7 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    3765           7 :     const bool bPromoteToMulti = CPLTestBool(
    3766             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    3767           7 :     const bool bUsePreparedGeometries = CPLTestBool(
    3768             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    3769           7 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    3770             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    3771             : 
    3772             :     // check for GEOS
    3773           7 :     if (!OGRGeometryFactory::haveGEOS())
    3774             :     {
    3775           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3776             :                  "OGRLayer::Union() requires GEOS support");
    3777           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    3778             :     }
    3779             : 
    3780             :     // get resources
    3781           7 :     ret = clone_spatial_filter(this, &pGeometryInputFilter);
    3782           7 :     if (ret != OGRERR_NONE)
    3783           0 :         goto done;
    3784           7 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    3785           7 :     if (ret != OGRERR_NONE)
    3786           0 :         goto done;
    3787           7 :     ret = create_field_map(poDefnInput, &mapInput);
    3788           7 :     if (ret != OGRERR_NONE)
    3789           0 :         goto done;
    3790           7 :     ret = create_field_map(poDefnMethod, &mapMethod);
    3791           7 :     if (ret != OGRERR_NONE)
    3792           0 :         goto done;
    3793           7 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    3794             :                             mapMethod, true, papszOptions);
    3795           7 :     if (ret != OGRERR_NONE)
    3796           0 :         goto done;
    3797           7 :     poDefnResult = pLayerResult->GetLayerDefn();
    3798           7 :     if (bKeepLowerDimGeom)
    3799             :     {
    3800             :         // require that the result layer is of geom type unknown
    3801           5 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    3802             :         {
    3803           0 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    3804             :                             "since the result layer does not allow it.");
    3805           0 :             bKeepLowerDimGeom = FALSE;
    3806             :         }
    3807             :     }
    3808             : 
    3809             :     // add features based on input layer
    3810          20 :     for (auto &&x : this)
    3811             :     {
    3812             : 
    3813          13 :         if (pfnProgress)
    3814             :         {
    3815           2 :             double p = progress_counter / progress_max;
    3816           2 :             if (p > progress_ticker)
    3817             :             {
    3818           1 :                 if (!pfnProgress(p, "", pProgressArg))
    3819             :                 {
    3820           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3821           0 :                     ret = OGRERR_FAILURE;
    3822           0 :                     goto done;
    3823             :                 }
    3824             :             }
    3825           2 :             progress_counter += 1.0;
    3826             :         }
    3827             : 
    3828             :         // set up the filter on method layer
    3829          13 :         CPLErrorReset();
    3830             :         OGRGeometry *x_geom =
    3831          13 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    3832          13 :         if (CPLGetLastErrorType() != CE_None)
    3833             :         {
    3834           0 :             if (!bSkipFailures)
    3835             :             {
    3836           0 :                 ret = OGRERR_FAILURE;
    3837           0 :                 goto done;
    3838             :             }
    3839             :             else
    3840             :             {
    3841           0 :                 CPLErrorReset();
    3842           0 :                 ret = OGRERR_NONE;
    3843             :             }
    3844             :         }
    3845          13 :         if (!x_geom)
    3846             :         {
    3847           0 :             continue;
    3848             :         }
    3849             : 
    3850           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    3851          13 :         if (bUsePreparedGeometries)
    3852             :         {
    3853          13 :             x_prepared_geom.reset(
    3854             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    3855          13 :             if (!x_prepared_geom)
    3856             :             {
    3857           0 :                 goto done;
    3858             :             }
    3859             :         }
    3860             : 
    3861             :         OGRGeometryUniquePtr x_geom_diff(
    3862             :             x_geom
    3863          13 :                 ->clone());  // this will be the geometry of the result feature
    3864          28 :         for (auto &&y : pLayerMethod)
    3865             :         {
    3866          15 :             OGRGeometry *y_geom = y->GetGeometryRef();
    3867          15 :             if (!y_geom)
    3868             :             {
    3869           0 :                 continue;
    3870             :             }
    3871             : 
    3872          15 :             CPLErrorReset();
    3873          30 :             if (x_prepared_geom &&
    3874          15 :                 !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
    3875          15 :                                                 OGRGeometry::ToHandle(y_geom))))
    3876             :             {
    3877           0 :                 if (CPLGetLastErrorType() == CE_None)
    3878             :                 {
    3879           0 :                     continue;
    3880             :                 }
    3881             :             }
    3882          15 :             if (CPLGetLastErrorType() != CE_None)
    3883             :             {
    3884           0 :                 if (!bSkipFailures)
    3885             :                 {
    3886           0 :                     ret = OGRERR_FAILURE;
    3887           0 :                     goto done;
    3888             :                 }
    3889             :                 else
    3890             :                 {
    3891           0 :                     CPLErrorReset();
    3892           0 :                     ret = OGRERR_NONE;
    3893             :                 }
    3894             :             }
    3895             : 
    3896          15 :             CPLErrorReset();
    3897          15 :             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
    3898          15 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    3899             :             {
    3900           0 :                 if (!bSkipFailures)
    3901             :                 {
    3902           0 :                     ret = OGRERR_FAILURE;
    3903           0 :                     goto done;
    3904             :                 }
    3905             :                 else
    3906             :                 {
    3907           0 :                     CPLErrorReset();
    3908           0 :                     ret = OGRERR_NONE;
    3909           0 :                     continue;
    3910             :                 }
    3911             :             }
    3912          30 :             if (poIntersection->IsEmpty() ||
    3913          15 :                 (!bKeepLowerDimGeom &&
    3914           6 :                  (x_geom->getDimension() == y_geom->getDimension() &&
    3915           6 :                   poIntersection->getDimension() < x_geom->getDimension())))
    3916             :             {
    3917             :                 // ok
    3918             :             }
    3919             :             else
    3920             :             {
    3921          11 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3922          11 :                 z->SetFieldsFrom(x.get(), mapInput);
    3923          11 :                 z->SetFieldsFrom(y.get(), mapMethod);
    3924          11 :                 if (bPromoteToMulti)
    3925           2 :                     poIntersection.reset(
    3926             :                         promote_to_multi(poIntersection.release()));
    3927          11 :                 z->SetGeometryDirectly(poIntersection.release());
    3928             : 
    3929          11 :                 if (x_geom_diff)
    3930             :                 {
    3931          11 :                     CPLErrorReset();
    3932             :                     OGRGeometryUniquePtr x_geom_diff_new(
    3933          11 :                         x_geom_diff->Difference(y_geom));
    3934          22 :                     if (CPLGetLastErrorType() != CE_None ||
    3935          11 :                         x_geom_diff_new == nullptr)
    3936             :                     {
    3937           0 :                         if (!bSkipFailures)
    3938             :                         {
    3939           0 :                             ret = OGRERR_FAILURE;
    3940           0 :                             goto done;
    3941             :                         }
    3942             :                         else
    3943             :                         {
    3944           0 :                             CPLErrorReset();
    3945             :                         }
    3946             :                     }
    3947             :                     else
    3948             :                     {
    3949          11 :                         x_geom_diff.swap(x_geom_diff_new);
    3950             :                     }
    3951             :                 }
    3952             : 
    3953          11 :                 ret = pLayerResult->CreateFeature(z.get());
    3954          11 :                 if (ret != OGRERR_NONE)
    3955             :                 {
    3956           0 :                     if (!bSkipFailures)
    3957             :                     {
    3958           0 :                         goto done;
    3959             :                     }
    3960             :                     else
    3961             :                     {
    3962           0 :                         CPLErrorReset();
    3963           0 :                         ret = OGRERR_NONE;
    3964             :                     }
    3965             :                 }
    3966             :             }
    3967             :         }
    3968          13 :         x_prepared_geom.reset();
    3969             : 
    3970          13 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    3971             :         {
    3972             :             // ok
    3973             :         }
    3974             :         else
    3975             :         {
    3976          11 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3977          11 :             z->SetFieldsFrom(x.get(), mapInput);
    3978          11 :             if (bPromoteToMulti)
    3979           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    3980          11 :             z->SetGeometryDirectly(x_geom_diff.release());
    3981          11 :             ret = pLayerResult->CreateFeature(z.get());
    3982          11 :             if (ret != OGRERR_NONE)
    3983             :             {
    3984           0 :                 if (!bSkipFailures)
    3985             :                 {
    3986           0 :                     goto done;
    3987             :                 }
    3988             :                 else
    3989             :                 {
    3990           0 :                     CPLErrorReset();
    3991           0 :                     ret = OGRERR_NONE;
    3992             :                 }
    3993             :             }
    3994             :         }
    3995             :     }
    3996             : 
    3997             :     // restore filter on method layer and add features based on it
    3998           7 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    3999          17 :     for (auto &&x : pLayerMethod)
    4000             :     {
    4001             : 
    4002          10 :         if (pfnProgress)
    4003             :         {
    4004           1 :             double p = progress_counter / progress_max;
    4005           1 :             if (p > progress_ticker)
    4006             :             {
    4007           1 :                 if (!pfnProgress(p, "", pProgressArg))
    4008             :                 {
    4009           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4010           0 :                     ret = OGRERR_FAILURE;
    4011           0 :                     goto done;
    4012             :                 }
    4013             :             }
    4014           1 :             progress_counter += 1.0;
    4015             :         }
    4016             : 
    4017             :         // set up the filter on input layer
    4018          10 :         CPLErrorReset();
    4019             :         OGRGeometry *x_geom =
    4020          10 :             set_filter_from(this, pGeometryInputFilter, x.get());
    4021          10 :         if (CPLGetLastErrorType() != CE_None)
    4022             :         {
    4023           0 :             if (!bSkipFailures)
    4024             :             {
    4025           0 :                 ret = OGRERR_FAILURE;
    4026           0 :                 goto done;
    4027             :             }
    4028             :             else
    4029             :             {
    4030           0 :                 CPLErrorReset();
    4031           0 :                 ret = OGRERR_NONE;
    4032             :             }
    4033             :         }
    4034          10 :         if (!x_geom)
    4035             :         {
    4036           0 :             continue;
    4037             :         }
    4038             : 
    4039             :         OGRGeometryUniquePtr x_geom_diff(
    4040             :             x_geom
    4041          10 :                 ->clone());  // this will be the geometry of the result feature
    4042          25 :         for (auto &&y : this)
    4043             :         {
    4044          15 :             OGRGeometry *y_geom = y->GetGeometryRef();
    4045          15 :             if (!y_geom)
    4046             :             {
    4047           0 :                 continue;
    4048             :             }
    4049             : 
    4050          15 :             if (x_geom_diff)
    4051             :             {
    4052          15 :                 CPLErrorReset();
    4053             :                 OGRGeometryUniquePtr x_geom_diff_new(
    4054          15 :                     x_geom_diff->Difference(y_geom));
    4055          30 :                 if (CPLGetLastErrorType() != CE_None ||
    4056          15 :                     x_geom_diff_new == nullptr)
    4057             :                 {
    4058           0 :                     if (!bSkipFailures)
    4059             :                     {
    4060           0 :                         ret = OGRERR_FAILURE;
    4061           0 :                         goto done;
    4062             :                     }
    4063             :                     else
    4064             :                     {
    4065           0 :                         CPLErrorReset();
    4066           0 :                         ret = OGRERR_NONE;
    4067             :                     }
    4068             :                 }
    4069             :                 else
    4070             :                 {
    4071          15 :                     x_geom_diff.swap(x_geom_diff_new);
    4072             :                 }
    4073             :             }
    4074             :         }
    4075             : 
    4076          10 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    4077             :         {
    4078             :             // ok
    4079             :         }
    4080             :         else
    4081             :         {
    4082           7 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4083           7 :             z->SetFieldsFrom(x.get(), mapMethod);
    4084           7 :             if (bPromoteToMulti)
    4085           1 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    4086           7 :             z->SetGeometryDirectly(x_geom_diff.release());
    4087           7 :             ret = pLayerResult->CreateFeature(z.get());
    4088           7 :             if (ret != OGRERR_NONE)
    4089             :             {
    4090           0 :                 if (!bSkipFailures)
    4091             :                 {
    4092           0 :                     goto done;
    4093             :                 }
    4094             :                 else
    4095             :                 {
    4096           0 :                     CPLErrorReset();
    4097           0 :                     ret = OGRERR_NONE;
    4098             :                 }
    4099             :             }
    4100             :         }
    4101             :     }
    4102           7 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    4103             :     {
    4104           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4105           0 :         ret = OGRERR_FAILURE;
    4106           0 :         goto done;
    4107             :     }
    4108           7 : done:
    4109             :     // release resources
    4110           7 :     SetSpatialFilter(pGeometryInputFilter);
    4111           7 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4112           7 :     if (pGeometryMethodFilter)
    4113           0 :         delete pGeometryMethodFilter;
    4114           7 :     if (pGeometryInputFilter)
    4115           0 :         delete pGeometryInputFilter;
    4116           7 :     if (mapInput)
    4117           4 :         VSIFree(mapInput);
    4118           7 :     if (mapMethod)
    4119           3 :         VSIFree(mapMethod);
    4120           7 :     return ret;
    4121             : }
    4122             : 
    4123             : /************************************************************************/
    4124             : /*                           OGR_L_Union()                              */
    4125             : /************************************************************************/
    4126             : 
    4127             : /**
    4128             :  * \brief Union of two layers.
    4129             :  *
    4130             :  * The result layer contains features whose geometries represent areas
    4131             :  * that are in either in the input layer, in the method layer, or in
    4132             :  * both. The features in the result layer have attributes from both
    4133             :  * input and method layers. For features which represent areas that
    4134             :  * are only in the input or in the method layer the respective
    4135             :  * attributes have undefined values. The schema of the result layer
    4136             :  * can be set by the user or, if it is empty, is initialized to
    4137             :  * contain all fields in the input and method layers.
    4138             :  *
    4139             :  * \note If the schema of the result is set by user and contains
    4140             :  * fields that have the same name as a field in input and in method
    4141             :  * layer, then the attribute in the result feature will get the value
    4142             :  * from the feature of the method layer (even if it is undefined).
    4143             :  *
    4144             :  * \note For best performance use the minimum amount of features in
    4145             :  * the method layer and copy it into a memory layer.
    4146             :  *
    4147             :  * \note This method relies on GEOS support. Do not use unless the
    4148             :  * GEOS support is compiled in.
    4149             :  *
    4150             :  * The recognized list of options is :
    4151             :  * <ul>
    4152             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4153             :  *     feature could not be inserted or a GEOS call failed.
    4154             :  * </li>
    4155             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4156             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4157             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4158             :  * </li>
    4159             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4160             :  *     will be created from the fields of the input layer.
    4161             :  * </li>
    4162             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4163             :  *     will be created from the fields of the method layer.
    4164             :  * </li>
    4165             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    4166             :  *     geometries to pretest intersection of features of method layer
    4167             :  *     with features of this layer.
    4168             :  * </li>
    4169             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    4170             :  *     result features with lower dimension geometry that would
    4171             :  *     otherwise be added to the result layer. The default is YES, to add
    4172             :  *     features with lower dimension geometry, but only if the result layer
    4173             :  *     has an unknown geometry type.
    4174             :  * </li>
    4175             :  * </ul>
    4176             :  *
    4177             :  * This function is the same as the C++ method OGRLayer::Union().
    4178             :  *
    4179             :  * @param pLayerInput the input layer. Should not be NULL.
    4180             :  *
    4181             :  * @param pLayerMethod the method layer. Should not be NULL.
    4182             :  *
    4183             :  * @param pLayerResult the layer where the features resulting from the
    4184             :  * operation are inserted. Should not be NULL. See above the note
    4185             :  * about the schema.
    4186             :  *
    4187             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4188             :  *
    4189             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4190             :  * reporting progress or NULL.
    4191             :  *
    4192             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4193             :  *
    4194             :  * @return an error code if there was an error or the execution was
    4195             :  * interrupted, OGRERR_NONE otherwise.
    4196             :  *
    4197             :  * @note The first geometry field is always used.
    4198             :  *
    4199             :  * @since OGR 1.10
    4200             :  */
    4201             : 
    4202           7 : OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    4203             :                    OGRLayerH pLayerResult, char **papszOptions,
    4204             :                    GDALProgressFunc pfnProgress, void *pProgressArg)
    4205             : 
    4206             : {
    4207           7 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    4208           7 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    4209           7 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    4210             : 
    4211             :     return OGRLayer::FromHandle(pLayerInput)
    4212           7 :         ->Union(OGRLayer::FromHandle(pLayerMethod),
    4213             :                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    4214           7 :                 pProgressArg);
    4215             : }
    4216             : 
    4217             : /************************************************************************/
    4218             : /*                          SymDifference()                             */
    4219             : /************************************************************************/
    4220             : 
    4221             : /**
    4222             :  * \brief Symmetrical difference of two layers.
    4223             :  *
    4224             :  * The result layer contains features whose geometries represent areas
    4225             :  * that are in either in the input layer or in the method layer but
    4226             :  * not in both. The features in the result layer have attributes from
    4227             :  * both input and method layers. For features which represent areas
    4228             :  * that are only in the input or in the method layer the respective
    4229             :  * attributes have undefined values. The schema of the result layer
    4230             :  * can be set by the user or, if it is empty, is initialized to
    4231             :  * contain all fields in the input and method layers.
    4232             :  *
    4233             :  * \note If the schema of the result is set by user and contains
    4234             :  * fields that have the same name as a field in input and in method
    4235             :  * layer, then the attribute in the result feature will get the value
    4236             :  * from the feature of the method layer (even if it is undefined).
    4237             :  *
    4238             :  * \note For best performance use the minimum amount of features in
    4239             :  * the method layer and copy it into a memory layer.
    4240             :  *
    4241             :  * \note This method relies on GEOS support. Do not use unless the
    4242             :  * GEOS support is compiled in.
    4243             :  *
    4244             :  * The recognized list of options is :
    4245             :  * <ul>
    4246             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4247             :  *     feature could not be inserted or a GEOS call failed.
    4248             :  * </li>
    4249             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
    4250             :  *     into MultiPolygons, or LineStrings to MultiLineStrings.
    4251             :  * </li>
    4252             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4253             :  *     will be created from the fields of the input layer.
    4254             :  * </li>
    4255             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4256             :  *     will be created from the fields of the method layer.
    4257             :  * </li>
    4258             :  * </ul>
    4259             :  *
    4260             :  * This method is the same as the C function OGR_L_SymDifference().
    4261             :  *
    4262             :  * @param pLayerMethod the method layer. Should not be NULL.
    4263             :  *
    4264             :  * @param pLayerResult the layer where the features resulting from the
    4265             :  * operation are inserted. Should not be NULL. See above the note
    4266             :  * about the schema.
    4267             :  *
    4268             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4269             :  *
    4270             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4271             :  * reporting progress or NULL.
    4272             :  *
    4273             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4274             :  *
    4275             :  * @return an error code if there was an error or the execution was
    4276             :  * interrupted, OGRERR_NONE otherwise.
    4277             :  *
    4278             :  * @note The first geometry field is always used.
    4279             :  *
    4280             :  * @since OGR 1.10
    4281             :  */
    4282             : 
    4283           4 : OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    4284             :                                char **papszOptions,
    4285             :                                GDALProgressFunc pfnProgress, void *pProgressArg)
    4286             : {
    4287           4 :     OGRErr ret = OGRERR_NONE;
    4288           4 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    4289           4 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    4290           4 :     OGRFeatureDefn *poDefnResult = nullptr;
    4291           4 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    4292           4 :     OGRGeometry *pGeometryInputFilter = nullptr;
    4293           4 :     int *mapInput = nullptr;
    4294           4 :     int *mapMethod = nullptr;
    4295             :     double progress_max =
    4296           4 :         static_cast<double>(GetFeatureCount(FALSE)) +
    4297           4 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    4298           4 :     double progress_counter = 0;
    4299           4 :     double progress_ticker = 0;
    4300             :     const bool bSkipFailures =
    4301           4 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    4302           4 :     const bool bPromoteToMulti = CPLTestBool(
    4303             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    4304             : 
    4305             :     // check for GEOS
    4306           4 :     if (!OGRGeometryFactory::haveGEOS())
    4307             :     {
    4308           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4309             :                  "OGRLayer::SymDifference() requires GEOS support");
    4310           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    4311             :     }
    4312             : 
    4313             :     // get resources
    4314           4 :     ret = clone_spatial_filter(this, &pGeometryInputFilter);
    4315           4 :     if (ret != OGRERR_NONE)
    4316           0 :         goto done;
    4317           4 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    4318           4 :     if (ret != OGRERR_NONE)
    4319           0 :         goto done;
    4320           4 :     ret = create_field_map(poDefnInput, &mapInput);
    4321           4 :     if (ret != OGRERR_NONE)
    4322           0 :         goto done;
    4323           4 :     ret = create_field_map(poDefnMethod, &mapMethod);
    4324           4 :     if (ret != OGRERR_NONE)
    4325           0 :         goto done;
    4326           4 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    4327             :                             mapMethod, true, papszOptions);
    4328           4 :     if (ret != OGRERR_NONE)
    4329           0 :         goto done;
    4330           4 :     poDefnResult = pLayerResult->GetLayerDefn();
    4331             : 
    4332             :     // add features based on input layer
    4333          12 :     for (auto &&x : this)
    4334             :     {
    4335             : 
    4336           8 :         if (pfnProgress)
    4337             :         {
    4338           2 :             double p = progress_counter / progress_max;
    4339           2 :             if (p > progress_ticker)
    4340             :             {
    4341           1 :                 if (!pfnProgress(p, "", pProgressArg))
    4342             :                 {
    4343           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4344           0 :                     ret = OGRERR_FAILURE;
    4345           0 :                     goto done;
    4346             :                 }
    4347             :             }
    4348           2 :             progress_counter += 1.0;
    4349             :         }
    4350             : 
    4351             :         // set up the filter on method layer
    4352           8 :         CPLErrorReset();
    4353             :         OGRGeometry *x_geom =
    4354           8 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    4355           8 :         if (CPLGetLastErrorType() != CE_None)
    4356             :         {
    4357           0 :             if (!bSkipFailures)
    4358             :             {
    4359           0 :                 ret = OGRERR_FAILURE;
    4360           0 :                 goto done;
    4361             :             }
    4362             :             else
    4363             :             {
    4364           0 :                 CPLErrorReset();
    4365           0 :                 ret = OGRERR_NONE;
    4366             :             }
    4367             :         }
    4368           8 :         if (!x_geom)
    4369             :         {
    4370           0 :             continue;
    4371             :         }
    4372             : 
    4373             :         OGRGeometryUniquePtr geom(
    4374             :             x_geom
    4375           8 :                 ->clone());  // this will be the geometry of the result feature
    4376          15 :         for (auto &&y : pLayerMethod)
    4377             :         {
    4378           9 :             OGRGeometry *y_geom = y->GetGeometryRef();
    4379           9 :             if (!y_geom)
    4380             :             {
    4381           0 :                 continue;
    4382             :             }
    4383           9 :             if (geom)
    4384             :             {
    4385           9 :                 CPLErrorReset();
    4386           9 :                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    4387           9 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    4388             :                 {
    4389           0 :                     if (!bSkipFailures)
    4390             :                     {
    4391           0 :                         ret = OGRERR_FAILURE;
    4392           0 :                         goto done;
    4393             :                     }
    4394             :                     else
    4395             :                     {
    4396           0 :                         CPLErrorReset();
    4397           0 :                         ret = OGRERR_NONE;
    4398             :                     }
    4399             :                 }
    4400             :                 else
    4401             :                 {
    4402           9 :                     geom.swap(geom_new);
    4403             :                 }
    4404             :             }
    4405           9 :             if (geom && geom->IsEmpty())
    4406           2 :                 break;
    4407             :         }
    4408             : 
    4409           8 :         if (geom && !geom->IsEmpty())
    4410             :         {
    4411           6 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4412           6 :             z->SetFieldsFrom(x.get(), mapInput);
    4413           6 :             if (bPromoteToMulti)
    4414           2 :                 geom.reset(promote_to_multi(geom.release()));
    4415           6 :             z->SetGeometryDirectly(geom.release());
    4416           6 :             ret = pLayerResult->CreateFeature(z.get());
    4417           6 :             if (ret != OGRERR_NONE)
    4418             :             {
    4419           0 :                 if (!bSkipFailures)
    4420             :                 {
    4421           0 :                     goto done;
    4422             :                 }
    4423             :                 else
    4424             :                 {
    4425           0 :                     CPLErrorReset();
    4426           0 :                     ret = OGRERR_NONE;
    4427             :                 }
    4428             :             }
    4429             :         }
    4430             :     }
    4431             : 
    4432             :     // restore filter on method layer and add features based on it
    4433           4 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4434          10 :     for (auto &&x : pLayerMethod)
    4435             :     {
    4436             : 
    4437           6 :         if (pfnProgress)
    4438             :         {
    4439           2 :             double p = progress_counter / progress_max;
    4440           2 :             if (p > progress_ticker)
    4441             :             {
    4442           2 :                 if (!pfnProgress(p, "", pProgressArg))
    4443             :                 {
    4444           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4445           0 :                     ret = OGRERR_FAILURE;
    4446           0 :                     goto done;
    4447             :                 }
    4448             :             }
    4449           2 :             progress_counter += 1.0;
    4450             :         }
    4451             : 
    4452             :         // set up the filter on input layer
    4453           6 :         CPLErrorReset();
    4454             :         OGRGeometry *x_geom =
    4455           6 :             set_filter_from(this, pGeometryInputFilter, x.get());
    4456           6 :         if (CPLGetLastErrorType() != CE_None)
    4457             :         {
    4458           0 :             if (!bSkipFailures)
    4459             :             {
    4460           0 :                 ret = OGRERR_FAILURE;
    4461           0 :                 goto done;
    4462             :             }
    4463             :             else
    4464             :             {
    4465           0 :                 CPLErrorReset();
    4466           0 :                 ret = OGRERR_NONE;
    4467             :             }
    4468             :         }
    4469           6 :         if (!x_geom)
    4470             :         {
    4471           0 :             continue;
    4472             :         }
    4473             : 
    4474             :         OGRGeometryUniquePtr geom(
    4475             :             x_geom
    4476           6 :                 ->clone());  // this will be the geometry of the result feature
    4477          13 :         for (auto &&y : this)
    4478             :         {
    4479           9 :             OGRGeometry *y_geom = y->GetGeometryRef();
    4480           9 :             if (!y_geom)
    4481           0 :                 continue;
    4482           9 :             if (geom)
    4483             :             {
    4484           9 :                 CPLErrorReset();
    4485           9 :                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    4486           9 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    4487             :                 {
    4488           0 :                     if (!bSkipFailures)
    4489             :                     {
    4490           0 :                         ret = OGRERR_FAILURE;
    4491           0 :                         goto done;
    4492             :                     }
    4493             :                     else
    4494             :                     {
    4495           0 :                         CPLErrorReset();
    4496           0 :                         ret = OGRERR_NONE;
    4497             :                     }
    4498             :                 }
    4499             :                 else
    4500             :                 {
    4501           9 :                     geom.swap(geom_new);
    4502             :                 }
    4503             :             }
    4504           9 :             if (geom == nullptr || geom->IsEmpty())
    4505           2 :                 break;
    4506             :         }
    4507             : 
    4508           6 :         if (geom && !geom->IsEmpty())
    4509             :         {
    4510           4 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4511           4 :             z->SetFieldsFrom(x.get(), mapMethod);
    4512           4 :             if (bPromoteToMulti)
    4513           1 :                 geom.reset(promote_to_multi(geom.release()));
    4514           4 :             z->SetGeometryDirectly(geom.release());
    4515           4 :             ret = pLayerResult->CreateFeature(z.get());
    4516           4 :             if (ret != OGRERR_NONE)
    4517             :             {
    4518           0 :                 if (!bSkipFailures)
    4519             :                 {
    4520           0 :                     goto done;
    4521             :                 }
    4522             :                 else
    4523             :                 {
    4524           0 :                     CPLErrorReset();
    4525           0 :                     ret = OGRERR_NONE;
    4526             :                 }
    4527             :             }
    4528             :         }
    4529             :     }
    4530           4 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    4531             :     {
    4532           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4533           0 :         ret = OGRERR_FAILURE;
    4534           0 :         goto done;
    4535             :     }
    4536           4 : done:
    4537             :     // release resources
    4538           4 :     SetSpatialFilter(pGeometryInputFilter);
    4539           4 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4540           4 :     if (pGeometryMethodFilter)
    4541           0 :         delete pGeometryMethodFilter;
    4542           4 :     if (pGeometryInputFilter)
    4543           0 :         delete pGeometryInputFilter;
    4544           4 :     if (mapInput)
    4545           3 :         VSIFree(mapInput);
    4546           4 :     if (mapMethod)
    4547           3 :         VSIFree(mapMethod);
    4548           4 :     return ret;
    4549             : }
    4550             : 
    4551             : /************************************************************************/
    4552             : /*                        OGR_L_SymDifference()                         */
    4553             : /************************************************************************/
    4554             : 
    4555             : /**
    4556             :  * \brief Symmetrical difference of two layers.
    4557             :  *
    4558             :  * The result layer contains features whose geometries represent areas
    4559             :  * that are in either in the input layer or in the method layer but
    4560             :  * not in both. The features in the result layer have attributes from
    4561             :  * both input and method layers. For features which represent areas
    4562             :  * that are only in the input or in the method layer the respective
    4563             :  * attributes have undefined values. The schema of the result layer
    4564             :  * can be set by the user or, if it is empty, is initialized to
    4565             :  * contain all fields in the input and method layers.
    4566             :  *
    4567             :  * \note If the schema of the result is set by user and contains
    4568             :  * fields that have the same name as a field in input and in method
    4569             :  * layer, then the attribute in the result feature will get the value
    4570             :  * from the feature of the method layer (even if it is undefined).
    4571             :  *
    4572             :  * \note For best performance use the minimum amount of features in
    4573             :  * the method layer and copy it into a memory layer.
    4574             :  *
    4575             :  * \note This method relies on GEOS support. Do not use unless the
    4576             :  * GEOS support is compiled in.
    4577             :  *
    4578             :  * The recognized list of options is :
    4579             :  * <ul>
    4580             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4581             :  *     feature could not be inserted or a GEOS call failed.
    4582             :  * </li>
    4583             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4584             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4585             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4586             :  * </li>
    4587             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4588             :  *     will be created from the fields of the input layer.
    4589             :  * </li>
    4590             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4591             :  *     will be created from the fields of the method layer.
    4592             :  * </li>
    4593             :  * </ul>
    4594             :  *
    4595             :  * This function is the same as the C++ method OGRLayer::SymDifference().
    4596             :  *
    4597             :  * @param pLayerInput the input layer. Should not be NULL.
    4598             :  *
    4599             :  * @param pLayerMethod the method layer. Should not be NULL.
    4600             :  *
    4601             :  * @param pLayerResult the layer where the features resulting from the
    4602             :  * operation are inserted. Should not be NULL. See above the note
    4603             :  * about the schema.
    4604             :  *
    4605             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4606             :  *
    4607             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4608             :  * reporting progress or NULL.
    4609             :  *
    4610             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4611             :  *
    4612             :  * @return an error code if there was an error or the execution was
    4613             :  * interrupted, OGRERR_NONE otherwise.
    4614             :  *
    4615             :  * @note The first geometry field is always used.
    4616             :  *
    4617             :  * @since OGR 1.10
    4618             :  */
    4619             : 
    4620           4 : OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    4621             :                            OGRLayerH pLayerResult, char **papszOptions,
    4622             :                            GDALProgressFunc pfnProgress, void *pProgressArg)
    4623             : 
    4624             : {
    4625           4 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
    4626             :                       OGRERR_INVALID_HANDLE);
    4627           4 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
    4628             :                       OGRERR_INVALID_HANDLE);
    4629           4 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
    4630             :                       OGRERR_INVALID_HANDLE);
    4631             : 
    4632             :     return OGRLayer::FromHandle(pLayerInput)
    4633           4 :         ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
    4634             :                         OGRLayer::FromHandle(pLayerResult), papszOptions,
    4635           4 :                         pfnProgress, pProgressArg);
    4636             : }
    4637             : 
    4638             : /************************************************************************/
    4639             : /*                            Identity()                                */
    4640             : /************************************************************************/
    4641             : 
    4642             : /**
    4643             :  * \brief Identify the features of this layer with the ones from the
    4644             :  * identity layer.
    4645             :  *
    4646             :  * The result layer contains features whose geometries represent areas
    4647             :  * that are in the input layer. The features in the result layer have
    4648             :  * attributes from both input and method layers. The schema of the
    4649             :  * result layer can be set by the user or, if it is empty, is
    4650             :  * initialized to contain all fields in input and method layers.
    4651             :  *
    4652             :  * \note If the schema of the result is set by user and contains
    4653             :  * fields that have the same name as a field in input and in method
    4654             :  * layer, then the attribute in the result feature will get the value
    4655             :  * from the feature of the method layer (even if it is undefined).
    4656             :  *
    4657             :  * \note For best performance use the minimum amount of features in
    4658             :  * the method layer and copy it into a memory layer.
    4659             :  *
    4660             :  * \note This method relies on GEOS support. Do not use unless the
    4661             :  * GEOS support is compiled in.
    4662             :  *
    4663             :  * The recognized list of options is :
    4664             :  * <ul>
    4665             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4666             :  *     feature could not be inserted or a GEOS call failed.
    4667             :  * </li>
    4668             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4669             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4670             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4671             :  * </li>
    4672             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4673             :  *     will be created from the fields of the input layer.
    4674             :  * </li>
    4675             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4676             :  *     will be created from the fields of the method layer.
    4677             :  * </li>
    4678             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    4679             :  *     geometries to pretest intersection of features of method layer
    4680             :  *     with features of this layer.
    4681             :  * </li>
    4682             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    4683             :  *     result features with lower dimension geometry that would
    4684             :  *     otherwise be added to the result layer. The default is YES, to add
    4685             :  *     features with lower dimension geometry, but only if the result layer
    4686             :  *     has an unknown geometry type.
    4687             :  * </li>
    4688             :  * </ul>
    4689             :  *
    4690             :  * This method is the same as the C function OGR_L_Identity().
    4691             :  *
    4692             :  * @param pLayerMethod the method layer. Should not be NULL.
    4693             :  *
    4694             :  * @param pLayerResult the layer where the features resulting from the
    4695             :  * operation are inserted. Should not be NULL. See above the note
    4696             :  * about the schema.
    4697             :  *
    4698             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4699             :  *
    4700             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4701             :  * reporting progress or NULL.
    4702             :  *
    4703             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4704             :  *
    4705             :  * @return an error code if there was an error or the execution was
    4706             :  * interrupted, OGRERR_NONE otherwise.
    4707             :  *
    4708             :  * @note The first geometry field is always used.
    4709             :  *
    4710             :  * @since OGR 1.10
    4711             :  */
    4712             : 
    4713           6 : OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    4714             :                           char **papszOptions, GDALProgressFunc pfnProgress,
    4715             :                           void *pProgressArg)
    4716             : {
    4717           6 :     OGRErr ret = OGRERR_NONE;
    4718           6 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    4719           6 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    4720           6 :     OGRFeatureDefn *poDefnResult = nullptr;
    4721           6 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    4722           6 :     int *mapInput = nullptr;
    4723           6 :     int *mapMethod = nullptr;
    4724           6 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    4725           6 :     double progress_counter = 0;
    4726           6 :     double progress_ticker = 0;
    4727             :     const bool bSkipFailures =
    4728           6 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    4729           6 :     const bool bPromoteToMulti = CPLTestBool(
    4730             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    4731           6 :     const bool bUsePreparedGeometries = CPLTestBool(
    4732             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    4733           6 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    4734             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    4735             : 
    4736             :     // check for GEOS
    4737           6 :     if (!OGRGeometryFactory::haveGEOS())
    4738             :     {
    4739           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4740             :                  "OGRLayer::Identity() requires GEOS support");
    4741           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    4742             :     }
    4743           6 :     if (bKeepLowerDimGeom)
    4744             :     {
    4745             :         // require that the result layer is of geom type unknown
    4746           4 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    4747             :         {
    4748           0 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    4749             :                             "since the result layer does not allow it.");
    4750           0 :             bKeepLowerDimGeom = FALSE;
    4751             :         }
    4752             :     }
    4753             : 
    4754             :     // get resources
    4755           6 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    4756           6 :     if (ret != OGRERR_NONE)
    4757           0 :         goto done;
    4758           6 :     ret = create_field_map(poDefnInput, &mapInput);
    4759           6 :     if (ret != OGRERR_NONE)
    4760           0 :         goto done;
    4761           6 :     ret = create_field_map(poDefnMethod, &mapMethod);
    4762           6 :     if (ret != OGRERR_NONE)
    4763           0 :         goto done;
    4764           6 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    4765             :                             mapMethod, true, papszOptions);
    4766           6 :     if (ret != OGRERR_NONE)
    4767           0 :         goto done;
    4768           6 :     poDefnResult = pLayerResult->GetLayerDefn();
    4769             : 
    4770             :     // split the features in input layer to the result layer
    4771          18 :     for (auto &&x : this)
    4772             :     {
    4773             : 
    4774          12 :         if (pfnProgress)
    4775             :         {
    4776           2 :             double p = progress_counter / progress_max;
    4777           2 :             if (p > progress_ticker)
    4778             :             {
    4779           1 :                 if (!pfnProgress(p, "", pProgressArg))
    4780             :                 {
    4781           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4782           0 :                     ret = OGRERR_FAILURE;
    4783           0 :                     goto done;
    4784             :                 }
    4785             :             }
    4786           2 :             progress_counter += 1.0;
    4787             :         }
    4788             : 
    4789             :         // set up the filter on method layer
    4790          12 :         CPLErrorReset();
    4791             :         OGRGeometry *x_geom =
    4792          12 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    4793          12 :         if (CPLGetLastErrorType() != CE_None)
    4794             :         {
    4795           0 :             if (!bSkipFailures)
    4796             :             {
    4797           0 :                 ret = OGRERR_FAILURE;
    4798           0 :                 goto done;
    4799             :             }
    4800             :             else
    4801             :             {
    4802           0 :                 CPLErrorReset();
    4803           0 :                 ret = OGRERR_NONE;
    4804             :             }
    4805             :         }
    4806          12 :         if (!x_geom)
    4807             :         {
    4808           0 :             continue;
    4809             :         }
    4810             : 
    4811           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    4812          12 :         if (bUsePreparedGeometries)
    4813             :         {
    4814          12 :             x_prepared_geom.reset(
    4815             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    4816          12 :             if (!x_prepared_geom)
    4817             :             {
    4818           0 :                 goto done;
    4819             :             }
    4820             :         }
    4821             : 
    4822             :         OGRGeometryUniquePtr x_geom_diff(
    4823             :             x_geom
    4824          12 :                 ->clone());  // this will be the geometry of the result feature
    4825          26 :         for (auto &&y : pLayerMethod)
    4826             :         {
    4827          14 :             OGRGeometry *y_geom = y->GetGeometryRef();
    4828          14 :             if (!y_geom)
    4829           0 :                 continue;
    4830             : 
    4831          14 :             CPLErrorReset();
    4832          28 :             if (x_prepared_geom &&
    4833          14 :                 !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
    4834          14 :                                                 OGRGeometry::ToHandle(y_geom))))
    4835             :             {
    4836           0 :                 if (CPLGetLastErrorType() == CE_None)
    4837             :                 {
    4838           0 :                     continue;
    4839             :                 }
    4840             :             }
    4841          14 :             if (CPLGetLastErrorType() != CE_None)
    4842             :             {
    4843           0 :                 if (!bSkipFailures)
    4844             :                 {
    4845           0 :                     ret = OGRERR_FAILURE;
    4846           0 :                     goto done;
    4847             :                 }
    4848             :                 else
    4849             :                 {
    4850           0 :                     CPLErrorReset();
    4851           0 :                     ret = OGRERR_NONE;
    4852             :                 }
    4853             :             }
    4854             : 
    4855          14 :             CPLErrorReset();
    4856          14 :             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
    4857          14 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    4858             :             {
    4859           0 :                 if (!bSkipFailures)
    4860             :                 {
    4861           0 :                     ret = OGRERR_FAILURE;
    4862           0 :                     goto done;
    4863             :                 }
    4864             :                 else
    4865             :                 {
    4866           0 :                     CPLErrorReset();
    4867           0 :                     ret = OGRERR_NONE;
    4868             :                 }
    4869             :             }
    4870          28 :             else if (poIntersection->IsEmpty() ||
    4871          14 :                      (!bKeepLowerDimGeom &&
    4872           6 :                       (x_geom->getDimension() == y_geom->getDimension() &&
    4873           6 :                        poIntersection->getDimension() <
    4874           6 :                            x_geom->getDimension())))
    4875             :             {
    4876             :                 /* ok*/
    4877             :             }
    4878             :             else
    4879             :             {
    4880          10 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4881          10 :                 z->SetFieldsFrom(x.get(), mapInput);
    4882          10 :                 z->SetFieldsFrom(y.get(), mapMethod);
    4883          10 :                 if (bPromoteToMulti)
    4884           2 :                     poIntersection.reset(
    4885             :                         promote_to_multi(poIntersection.release()));
    4886          10 :                 z->SetGeometryDirectly(poIntersection.release());
    4887          10 :                 if (x_geom_diff)
    4888             :                 {
    4889          10 :                     CPLErrorReset();
    4890             :                     OGRGeometryUniquePtr x_geom_diff_new(
    4891          10 :                         x_geom_diff->Difference(y_geom));
    4892          20 :                     if (CPLGetLastErrorType() != CE_None ||
    4893          10 :                         x_geom_diff_new == nullptr)
    4894             :                     {
    4895           0 :                         if (!bSkipFailures)
    4896             :                         {
    4897           0 :                             ret = OGRERR_FAILURE;
    4898           0 :                             goto done;
    4899             :                         }
    4900             :                         else
    4901             :                         {
    4902           0 :                             CPLErrorReset();
    4903             :                         }
    4904             :                     }
    4905             :                     else
    4906             :                     {
    4907          10 :                         x_geom_diff.swap(x_geom_diff_new);
    4908             :                     }
    4909             :                 }
    4910          10 :                 ret = pLayerResult->CreateFeature(z.get());
    4911          10 :                 if (ret != OGRERR_NONE)
    4912             :                 {
    4913           0 :                     if (!bSkipFailures)
    4914             :                     {
    4915           0 :                         goto done;
    4916             :                     }
    4917             :                     else
    4918             :                     {
    4919           0 :                         CPLErrorReset();
    4920           0 :                         ret = OGRERR_NONE;
    4921             :                     }
    4922             :                 }
    4923             :             }
    4924             :         }
    4925             : 
    4926          12 :         x_prepared_geom.reset();
    4927             : 
    4928          12 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    4929             :         {
    4930             :             /* ok */
    4931             :         }
    4932             :         else
    4933             :         {
    4934          10 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4935          10 :             z->SetFieldsFrom(x.get(), mapInput);
    4936          10 :             if (bPromoteToMulti)
    4937           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    4938          10 :             z->SetGeometryDirectly(x_geom_diff.release());
    4939          10 :             ret = pLayerResult->CreateFeature(z.get());
    4940          10 :             if (ret != OGRERR_NONE)
    4941             :             {
    4942           0 :                 if (!bSkipFailures)
    4943             :                 {
    4944           0 :                     goto done;
    4945             :                 }
    4946             :                 else
    4947             :                 {
    4948           0 :                     CPLErrorReset();
    4949           0 :                     ret = OGRERR_NONE;
    4950             :                 }
    4951             :             }
    4952             :         }
    4953             :     }
    4954           6 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    4955             :     {
    4956           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4957           0 :         ret = OGRERR_FAILURE;
    4958           0 :         goto done;
    4959             :     }
    4960           6 : done:
    4961             :     // release resources
    4962           6 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4963           6 :     if (pGeometryMethodFilter)
    4964           0 :         delete pGeometryMethodFilter;
    4965           6 :     if (mapInput)
    4966           3 :         VSIFree(mapInput);
    4967           6 :     if (mapMethod)
    4968           3 :         VSIFree(mapMethod);
    4969           6 :     return ret;
    4970             : }
    4971             : 
    4972             : /************************************************************************/
    4973             : /*                         OGR_L_Identity()                             */
    4974             : /************************************************************************/
    4975             : 
    4976             : /**
    4977             :  * \brief Identify the features of this layer with the ones from the
    4978             :  * identity layer.
    4979             :  *
    4980             :  * The result layer contains features whose geometries represent areas
    4981             :  * that are in the input layer. The features in the result layer have
    4982             :  * attributes from both input and method layers. The schema of the
    4983             :  * result layer can be set by the user or, if it is empty, is
    4984             :  * initialized to contain all fields in input and method layers.
    4985             :  *
    4986             :  * \note If the schema of the result is set by user and contains
    4987             :  * fields that have the same name as a field in input and in method
    4988             :  * layer, then the attribute in the result feature will get the value
    4989             :  * from the feature of the method layer (even if it is undefined).
    4990             :  *
    4991             :  * \note For best performance use the minimum amount of features in
    4992             :  * the method layer and copy it into a memory layer.
    4993             :  *
    4994             :  * \note This method relies on GEOS support. Do not use unless the
    4995             :  * GEOS support is compiled in.
    4996             :  *
    4997             :  * The recognized list of options is :
    4998             :  * <ul>
    4999             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5000             :  *     feature could not be inserted or a GEOS call failed.
    5001             :  * </li>
    5002             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5003             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5004             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5005             :  * </li>
    5006             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5007             :  *     will be created from the fields of the input layer.
    5008             :  * </li>
    5009             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5010             :  *     will be created from the fields of the method layer.
    5011             :  * </li>
    5012             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    5013             :  *     geometries to pretest intersection of features of method layer
    5014             :  *     with features of this layer.
    5015             :  * </li>
    5016             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    5017             :  *     result features with lower dimension geometry that would
    5018             :  *     otherwise be added to the result layer. The default is YES, to add
    5019             :  *     features with lower dimension geometry, but only if the result layer
    5020             :  *     has an unknown geometry type.
    5021             :  * </li>
    5022             :  * </ul>
    5023             :  *
    5024             :  * This function is the same as the C++ method OGRLayer::Identity().
    5025             :  *
    5026             :  * @param pLayerInput the input layer. Should not be NULL.
    5027             :  *
    5028             :  * @param pLayerMethod the method layer. Should not be NULL.
    5029             :  *
    5030             :  * @param pLayerResult the layer where the features resulting from the
    5031             :  * operation are inserted. Should not be NULL. See above the note
    5032             :  * about the schema.
    5033             :  *
    5034             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5035             :  *
    5036             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5037             :  * reporting progress or NULL.
    5038             :  *
    5039             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5040             :  *
    5041             :  * @return an error code if there was an error or the execution was
    5042             :  * interrupted, OGRERR_NONE otherwise.
    5043             :  *
    5044             :  * @note The first geometry field is always used.
    5045             :  *
    5046             :  * @since OGR 1.10
    5047             :  */
    5048             : 
    5049           6 : OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    5050             :                       OGRLayerH pLayerResult, char **papszOptions,
    5051             :                       GDALProgressFunc pfnProgress, void *pProgressArg)
    5052             : 
    5053             : {
    5054           6 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    5055           6 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    5056           6 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    5057             : 
    5058             :     return OGRLayer::FromHandle(pLayerInput)
    5059           6 :         ->Identity(OGRLayer::FromHandle(pLayerMethod),
    5060             :                    OGRLayer::FromHandle(pLayerResult), papszOptions,
    5061           6 :                    pfnProgress, pProgressArg);
    5062             : }
    5063             : 
    5064             : /************************************************************************/
    5065             : /*                             Update()                                 */
    5066             : /************************************************************************/
    5067             : 
    5068             : /**
    5069             :  * \brief Update this layer with features from the update layer.
    5070             :  *
    5071             :  * The result layer contains features whose geometries represent areas
    5072             :  * that are either in the input layer or in the method layer. The
    5073             :  * features in the result layer have areas of the features of the
    5074             :  * method layer or those ares of the features of the input layer that
    5075             :  * are not covered by the method layer. The features of the result
    5076             :  * layer get their attributes from the input layer. The schema of the
    5077             :  * result layer can be set by the user or, if it is empty, is
    5078             :  * initialized to contain all fields in the input layer.
    5079             :  *
    5080             :  * \note If the schema of the result is set by user and contains
    5081             :  * fields that have the same name as a field in the method layer, then
    5082             :  * the attribute in the result feature the originates from the method
    5083             :  * layer will get the value from the feature of the method layer.
    5084             :  *
    5085             :  * \note For best performance use the minimum amount of features in
    5086             :  * the method layer and copy it into a memory layer.
    5087             :  *
    5088             :  * \note This method relies on GEOS support. Do not use unless the
    5089             :  * GEOS support is compiled in.
    5090             :  *
    5091             :  * The recognized list of options is :
    5092             :  * <ul>
    5093             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5094             :  *     feature could not be inserted or a GEOS call failed.
    5095             :  * </li>
    5096             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5097             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5098             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5099             :  * </li>
    5100             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5101             :  *     will be created from the fields of the input layer.
    5102             :  * </li>
    5103             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5104             :  *     will be created from the fields of the method layer.
    5105             :  * </li>
    5106             :  * </ul>
    5107             :  *
    5108             :  * This method is the same as the C function OGR_L_Update().
    5109             :  *
    5110             :  * @param pLayerMethod the method layer. Should not be NULL.
    5111             :  *
    5112             :  * @param pLayerResult the layer where the features resulting from the
    5113             :  * operation are inserted. Should not be NULL. See above the note
    5114             :  * about the schema.
    5115             :  *
    5116             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5117             :  *
    5118             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5119             :  * reporting progress or NULL.
    5120             :  *
    5121             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5122             :  *
    5123             :  * @return an error code if there was an error or the execution was
    5124             :  * interrupted, OGRERR_NONE otherwise.
    5125             :  *
    5126             :  * @note The first geometry field is always used.
    5127             :  *
    5128             :  * @since OGR 1.10
    5129             :  */
    5130             : 
    5131           5 : OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    5132             :                         char **papszOptions, GDALProgressFunc pfnProgress,
    5133             :                         void *pProgressArg)
    5134             : {
    5135           5 :     OGRErr ret = OGRERR_NONE;
    5136           5 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    5137           5 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    5138           5 :     OGRFeatureDefn *poDefnResult = nullptr;
    5139           5 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    5140           5 :     int *mapInput = nullptr;
    5141           5 :     int *mapMethod = nullptr;
    5142             :     double progress_max =
    5143           5 :         static_cast<double>(GetFeatureCount(FALSE)) +
    5144           5 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    5145           5 :     double progress_counter = 0;
    5146           5 :     double progress_ticker = 0;
    5147             :     const bool bSkipFailures =
    5148           5 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    5149           5 :     const bool bPromoteToMulti = CPLTestBool(
    5150             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    5151             : 
    5152             :     // check for GEOS
    5153           5 :     if (!OGRGeometryFactory::haveGEOS())
    5154             :     {
    5155           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    5156             :                  "OGRLayer::Update() requires GEOS support");
    5157           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    5158             :     }
    5159             : 
    5160             :     // get resources
    5161           5 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    5162           5 :     if (ret != OGRERR_NONE)
    5163           0 :         goto done;
    5164           5 :     ret = create_field_map(poDefnInput, &mapInput);
    5165           5 :     if (ret != OGRERR_NONE)
    5166           0 :         goto done;
    5167           5 :     ret = create_field_map(poDefnMethod, &mapMethod);
    5168           5 :     if (ret != OGRERR_NONE)
    5169           0 :         goto done;
    5170           5 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    5171             :                             mapMethod, false, papszOptions);
    5172           5 :     if (ret != OGRERR_NONE)
    5173           0 :         goto done;
    5174           5 :     poDefnResult = pLayerResult->GetLayerDefn();
    5175             : 
    5176             :     // add clipped features from the input layer
    5177          15 :     for (auto &&x : this)
    5178             :     {
    5179             : 
    5180          10 :         if (pfnProgress)
    5181             :         {
    5182           2 :             double p = progress_counter / progress_max;
    5183           2 :             if (p > progress_ticker)
    5184             :             {
    5185           1 :                 if (!pfnProgress(p, "", pProgressArg))
    5186             :                 {
    5187           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5188           0 :                     ret = OGRERR_FAILURE;
    5189           0 :                     goto done;
    5190             :                 }
    5191             :             }
    5192           2 :             progress_counter += 1.0;
    5193             :         }
    5194             : 
    5195             :         // set up the filter on method layer
    5196          10 :         CPLErrorReset();
    5197             :         OGRGeometry *x_geom =
    5198          10 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    5199          10 :         if (CPLGetLastErrorType() != CE_None)
    5200             :         {
    5201           0 :             if (!bSkipFailures)
    5202             :             {
    5203           0 :                 ret = OGRERR_FAILURE;
    5204           0 :                 goto done;
    5205             :             }
    5206             :             else
    5207             :             {
    5208           0 :                 CPLErrorReset();
    5209           0 :                 ret = OGRERR_NONE;
    5210             :             }
    5211             :         }
    5212          10 :         if (!x_geom)
    5213             :         {
    5214           0 :             continue;
    5215             :         }
    5216             : 
    5217             :         OGRGeometryUniquePtr x_geom_diff(
    5218          10 :             x_geom->clone());  // this will be the geometry of a result feature
    5219          24 :         for (auto &&y : pLayerMethod)
    5220             :         {
    5221          14 :             OGRGeometry *y_geom = y->GetGeometryRef();
    5222          14 :             if (!y_geom)
    5223           0 :                 continue;
    5224          14 :             if (x_geom_diff)
    5225             :             {
    5226          14 :                 CPLErrorReset();
    5227             :                 OGRGeometryUniquePtr x_geom_diff_new(
    5228          14 :                     x_geom_diff->Difference(y_geom));
    5229          28 :                 if (CPLGetLastErrorType() != CE_None ||
    5230          14 :                     x_geom_diff_new == nullptr)
    5231             :                 {
    5232           0 :                     if (!bSkipFailures)
    5233             :                     {
    5234           0 :                         ret = OGRERR_FAILURE;
    5235           0 :                         goto done;
    5236             :                     }
    5237             :                     else
    5238             :                     {
    5239           0 :                         CPLErrorReset();
    5240           0 :                         ret = OGRERR_NONE;
    5241             :                     }
    5242             :                 }
    5243             :                 else
    5244             :                 {
    5245          14 :                     x_geom_diff.swap(x_geom_diff_new);
    5246             :                 }
    5247             :             }
    5248             :         }
    5249             : 
    5250          10 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    5251             :         {
    5252             :             /* ok */
    5253             :         }
    5254             :         else
    5255             :         {
    5256           6 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    5257           6 :             z->SetFieldsFrom(x.get(), mapInput);
    5258           6 :             if (bPromoteToMulti)
    5259           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    5260           6 :             z->SetGeometryDirectly(x_geom_diff.release());
    5261           6 :             ret = pLayerResult->CreateFeature(z.get());
    5262           6 :             if (ret != OGRERR_NONE)
    5263             :             {
    5264           0 :                 if (!bSkipFailures)
    5265             :                 {
    5266           0 :                     goto done;
    5267             :                 }
    5268             :                 else
    5269             :                 {
    5270           0 :                     CPLErrorReset();
    5271           0 :                     ret = OGRERR_NONE;
    5272             :                 }
    5273             :             }
    5274             :         }
    5275             :     }
    5276             : 
    5277             :     // restore the original filter and add features from the update layer
    5278           5 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    5279          12 :     for (auto &&y : pLayerMethod)
    5280             :     {
    5281             : 
    5282           7 :         if (pfnProgress)
    5283             :         {
    5284           1 :             double p = progress_counter / progress_max;
    5285           1 :             if (p > progress_ticker)
    5286             :             {
    5287           1 :                 if (!pfnProgress(p, "", pProgressArg))
    5288             :                 {
    5289           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5290           0 :                     ret = OGRERR_FAILURE;
    5291           0 :                     goto done;
    5292             :                 }
    5293             :             }
    5294           1 :             progress_counter += 1.0;
    5295             :         }
    5296             : 
    5297           7 :         OGRGeometry *y_geom = y->StealGeometry();
    5298           7 :         if (!y_geom)
    5299           0 :             continue;
    5300           7 :         OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    5301           7 :         if (mapMethod)
    5302           3 :             z->SetFieldsFrom(y.get(), mapMethod);
    5303           7 :         z->SetGeometryDirectly(y_geom);
    5304           7 :         ret = pLayerResult->CreateFeature(z.get());
    5305           7 :         if (ret != OGRERR_NONE)
    5306             :         {
    5307           0 :             if (!bSkipFailures)
    5308             :             {
    5309           0 :                 goto done;
    5310             :             }
    5311             :             else
    5312             :             {
    5313           0 :                 CPLErrorReset();
    5314           0 :                 ret = OGRERR_NONE;
    5315             :             }
    5316             :         }
    5317             :     }
    5318           5 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    5319             :     {
    5320           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5321           0 :         ret = OGRERR_FAILURE;
    5322           0 :         goto done;
    5323             :     }
    5324           5 : done:
    5325             :     // release resources
    5326           5 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    5327           5 :     if (pGeometryMethodFilter)
    5328           0 :         delete pGeometryMethodFilter;
    5329           5 :     if (mapInput)
    5330           3 :         VSIFree(mapInput);
    5331           5 :     if (mapMethod)
    5332           3 :         VSIFree(mapMethod);
    5333           5 :     return ret;
    5334             : }
    5335             : 
    5336             : /************************************************************************/
    5337             : /*                          OGR_L_Update()                              */
    5338             : /************************************************************************/
    5339             : 
    5340             : /**
    5341             :  * \brief Update this layer with features from the update layer.
    5342             :  *
    5343             :  * The result layer contains features whose geometries represent areas
    5344             :  * that are either in the input layer or in the method layer. The
    5345             :  * features in the result layer have areas of the features of the
    5346             :  * method layer or those ares of the features of the input layer that
    5347             :  * are not covered by the method layer. The features of the result
    5348             :  * layer get their attributes from the input layer. The schema of the
    5349             :  * result layer can be set by the user or, if it is empty, is
    5350             :  * initialized to contain all fields in the input layer.
    5351             :  *
    5352             :  * \note If the schema of the result is set by user and contains
    5353             :  * fields that have the same name as a field in the method layer, then
    5354             :  * the attribute in the result feature the originates from the method
    5355             :  * layer will get the value from the feature of the method layer.
    5356             :  *
    5357             :  * \note For best performance use the minimum amount of features in
    5358             :  * the method layer and copy it into a memory layer.
    5359             :  *
    5360             :  * \note This method relies on GEOS support. Do not use unless the
    5361             :  * GEOS support is compiled in.
    5362             :  *
    5363             :  * The recognized list of options is :
    5364             :  * <ul>
    5365             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5366             :  *     feature could not be inserted or a GEOS call failed.
    5367             :  * </li>
    5368             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5369             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5370             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5371             :  * </li>
    5372             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5373             :  *     will be created from the fields of the input layer.
    5374             :  * </li>
    5375             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5376             :  *     will be created from the fields of the method layer.
    5377             :  * </li>
    5378             :  * </ul>
    5379             :  *
    5380             :  * This function is the same as the C++ method OGRLayer::Update().
    5381             :  *
    5382             :  * @param pLayerInput the input layer. Should not be NULL.
    5383             :  *
    5384             :  * @param pLayerMethod the method layer. Should not be NULL.
    5385             :  *
    5386             :  * @param pLayerResult the layer where the features resulting from the
    5387             :  * operation are inserted. Should not be NULL. See above the note
    5388             :  * about the schema.
    5389             :  *
    5390             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5391             :  *
    5392             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5393             :  * reporting progress or NULL.
    5394             :  *
    5395             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5396             :  *
    5397             :  * @return an error code if there was an error or the execution was
    5398             :  * interrupted, OGRERR_NONE otherwise.
    5399             :  *
    5400             :  * @note The first geometry field is always used.
    5401             :  *
    5402             :  * @since OGR 1.10
    5403             :  */
    5404             : 
    5405           5 : OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    5406             :                     OGRLayerH pLayerResult, char **papszOptions,
    5407             :                     GDALProgressFunc pfnProgress, void *pProgressArg)
    5408             : 
    5409             : {
    5410           5 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    5411           5 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    5412           5 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    5413             : 
    5414             :     return OGRLayer::FromHandle(pLayerInput)
    5415           5 :         ->Update(OGRLayer::FromHandle(pLayerMethod),
    5416             :                  OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    5417           5 :                  pProgressArg);
    5418             : }
    5419             : 
    5420             : /************************************************************************/
    5421             : /*                              Clip()                                  */
    5422             : /************************************************************************/
    5423             : 
    5424             : /**
    5425             :  * \brief Clip off areas that are not covered by the method layer.
    5426             :  *
    5427             :  * The result layer contains features whose geometries represent areas
    5428             :  * that are in the input layer and in the method layer. The features
    5429             :  * in the result layer have the (possibly clipped) areas of features
    5430             :  * in the input layer and the attributes from the same features. The
    5431             :  * schema of the result layer can be set by the user or, if it is
    5432             :  * empty, is initialized to contain all fields in the input layer.
    5433             :  *
    5434             :  * \note For best performance use the minimum amount of features in
    5435             :  * the method layer and copy it into a memory layer.
    5436             :  *
    5437             :  * \note This method relies on GEOS support. Do not use unless the
    5438             :  * GEOS support is compiled in.
    5439             :  *
    5440             :  * The recognized list of options is :
    5441             :  * <ul>
    5442             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5443             :  *     feature could not be inserted or a GEOS call failed.
    5444             :  * </li>
    5445             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5446             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5447             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5448             :  * </li>
    5449             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5450             :  *     will be created from the fields of the input layer.
    5451             :  * </li>
    5452             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5453             :  *     will be created from the fields of the method layer.
    5454             :  * </li>
    5455             :  * </ul>
    5456             :  *
    5457             :  * This method is the same as the C function OGR_L_Clip().
    5458             :  *
    5459             :  * @param pLayerMethod the method layer. Should not be NULL.
    5460             :  *
    5461             :  * @param pLayerResult the layer where the features resulting from the
    5462             :  * operation are inserted. Should not be NULL. See above the note
    5463             :  * about the schema.
    5464             :  *
    5465             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5466             :  *
    5467             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5468             :  * reporting progress or NULL.
    5469             :  *
    5470             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5471             :  *
    5472             :  * @return an error code if there was an error or the execution was
    5473             :  * interrupted, OGRERR_NONE otherwise.
    5474             :  *
    5475             :  * @note The first geometry field is always used.
    5476             :  *
    5477             :  * @since OGR 1.10
    5478             :  */
    5479             : 
    5480           3 : OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    5481             :                       char **papszOptions, GDALProgressFunc pfnProgress,
    5482             :                       void *pProgressArg)
    5483             : {
    5484           3 :     OGRErr ret = OGRERR_NONE;
    5485           3 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    5486           3 :     OGRFeatureDefn *poDefnResult = nullptr;
    5487           3 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    5488           3 :     int *mapInput = nullptr;
    5489           3 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    5490           3 :     double progress_counter = 0;
    5491           3 :     double progress_ticker = 0;
    5492             :     const bool bSkipFailures =
    5493           3 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    5494           3 :     const bool bPromoteToMulti = CPLTestBool(
    5495             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    5496             : 
    5497             :     // check for GEOS
    5498           3 :     if (!OGRGeometryFactory::haveGEOS())
    5499             :     {
    5500           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    5501             :                  "OGRLayer::Clip() requires GEOS support");
    5502           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    5503             :     }
    5504             : 
    5505           3 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    5506           3 :     if (ret != OGRERR_NONE)
    5507           0 :         goto done;
    5508           3 :     ret = create_field_map(poDefnInput, &mapInput);
    5509           3 :     if (ret != OGRERR_NONE)
    5510           0 :         goto done;
    5511           3 :     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
    5512             :                             nullptr, false, papszOptions);
    5513           3 :     if (ret != OGRERR_NONE)
    5514           0 :         goto done;
    5515             : 
    5516           3 :     poDefnResult = pLayerResult->GetLayerDefn();
    5517           9 :     for (auto &&x : this)
    5518             :     {
    5519             : 
    5520           6 :         if (pfnProgress)
    5521             :         {
    5522           2 :             double p = progress_counter / progress_max;
    5523           2 :             if (p > progress_ticker)
    5524             :             {
    5525           1 :                 if (!pfnProgress(p, "", pProgressArg))
    5526             :                 {
    5527           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5528           0 :                     ret = OGRERR_FAILURE;
    5529           0 :                     goto done;
    5530             :                 }
    5531             :             }
    5532           2 :             progress_counter += 1.0;
    5533             :         }
    5534             : 
    5535             :         // set up the filter on method layer
    5536           6 :         CPLErrorReset();
    5537             :         OGRGeometry *x_geom =
    5538           6 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    5539           6 :         if (CPLGetLastErrorType() != CE_None)
    5540             :         {
    5541           0 :             if (!bSkipFailures)
    5542             :             {
    5543           0 :                 ret = OGRERR_FAILURE;
    5544           0 :                 goto done;
    5545             :             }
    5546             :             else
    5547             :             {
    5548           0 :                 CPLErrorReset();
    5549           0 :                 ret = OGRERR_NONE;
    5550             :             }
    5551             :         }
    5552           6 :         if (!x_geom)
    5553             :         {
    5554           0 :             continue;
    5555             :         }
    5556             : 
    5557             :         OGRGeometryUniquePtr
    5558           0 :             geom;  // this will be the geometry of the result feature
    5559             :         // incrementally add area from y to geom
    5560          12 :         for (auto &&y : pLayerMethod)
    5561             :         {
    5562           6 :             OGRGeometry *y_geom = y->GetGeometryRef();
    5563           6 :             if (!y_geom)
    5564           0 :                 continue;
    5565           6 :             if (!geom)
    5566             :             {
    5567           6 :                 geom.reset(y_geom->clone());
    5568             :             }
    5569             :             else
    5570             :             {
    5571           0 :                 CPLErrorReset();
    5572           0 :                 OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
    5573           0 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    5574             :                 {
    5575           0 :                     if (!bSkipFailures)
    5576             :                     {
    5577           0 :                         ret = OGRERR_FAILURE;
    5578           0 :                         goto done;
    5579             :                     }
    5580             :                     else
    5581             :                     {
    5582           0 :                         CPLErrorReset();
    5583           0 :                         ret = OGRERR_NONE;
    5584             :                     }
    5585             :                 }
    5586             :                 else
    5587             :                 {
    5588           0 :                     geom.swap(geom_new);
    5589             :                 }
    5590             :             }
    5591             :         }
    5592             : 
    5593             :         // possibly add a new feature with area x intersection sum of y
    5594           6 :         if (geom)
    5595             :         {
    5596           6 :             CPLErrorReset();
    5597             :             OGRGeometryUniquePtr poIntersection(
    5598           6 :                 x_geom->Intersection(geom.get()));
    5599           6 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    5600             :             {
    5601           0 :                 if (!bSkipFailures)
    5602             :                 {
    5603           0 :                     ret = OGRERR_FAILURE;
    5604           0 :                     goto done;
    5605             :                 }
    5606             :                 else
    5607             :                 {
    5608           0 :                     CPLErrorReset();
    5609           0 :                     ret = OGRERR_NONE;
    5610             :                 }
    5611             :             }
    5612           6 :             else if (!poIntersection->IsEmpty())
    5613             :             {
    5614           6 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    5615           6 :                 z->SetFieldsFrom(x.get(), mapInput);
    5616           6 :                 if (bPromoteToMulti)
    5617           2 :                     poIntersection.reset(
    5618             :                         promote_to_multi(poIntersection.release()));
    5619           6 :                 z->SetGeometryDirectly(poIntersection.release());
    5620           6 :                 ret = pLayerResult->CreateFeature(z.get());
    5621           6 :                 if (ret != OGRERR_NONE)
    5622             :                 {
    5623           0 :                     if (!bSkipFailures)
    5624             :                     {
    5625           0 :                         goto done;
    5626             :                     }
    5627             :                     else
    5628             :                     {
    5629           0 :                         CPLErrorReset();
    5630           0 :                         ret = OGRERR_NONE;
    5631             :                     }
    5632             :                 }
    5633             :             }
    5634             :         }
    5635             :     }
    5636           3 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    5637             :     {
    5638           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5639           0 :         ret = OGRERR_FAILURE;
    5640           0 :         goto done;
    5641             :     }
    5642           3 : done:
    5643             :     // release resources
    5644           3 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    5645           3 :     if (pGeometryMethodFilter)
    5646           0 :         delete pGeometryMethodFilter;
    5647           3 :     if (mapInput)
    5648           3 :         VSIFree(mapInput);
    5649           3 :     return ret;
    5650             : }
    5651             : 
    5652             : /************************************************************************/
    5653             : /*                           OGR_L_Clip()                               */
    5654             : /************************************************************************/
    5655             : 
    5656             : /**
    5657             :  * \brief Clip off areas that are not covered by the method layer.
    5658             :  *
    5659             :  * The result layer contains features whose geometries represent areas
    5660             :  * that are in the input layer and in the method layer. The features
    5661             :  * in the result layer have the (possibly clipped) areas of features
    5662             :  * in the input layer and the attributes from the same features. The
    5663             :  * schema of the result layer can be set by the user or, if it is
    5664             :  * empty, is initialized to contain all fields in the input layer.
    5665             :  *
    5666             :  * \note For best performance use the minimum amount of features in
    5667             :  * the method layer and copy it into a memory layer.
    5668             :  *
    5669             :  * \note This method relies on GEOS support. Do not use unless the
    5670             :  * GEOS support is compiled in.
    5671             :  *
    5672             :  * The recognized list of options is :
    5673             :  * <ul>
    5674             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5675             :  *     feature could not be inserted or a GEOS call failed.
    5676             :  * </li>
    5677             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5678             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5679             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5680             :  * </li>
    5681             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5682             :  *     will be created from the fields of the input layer.
    5683             :  * </li>
    5684             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5685             :  *     will be created from the fields of the method layer.
    5686             :  * </li>
    5687             :  * </ul>
    5688             :  *
    5689             :  * This function is the same as the C++ method OGRLayer::Clip().
    5690             :  *
    5691             :  * @param pLayerInput the input layer. Should not be NULL.
    5692             :  *
    5693             :  * @param pLayerMethod the method layer. Should not be NULL.
    5694             :  *
    5695             :  * @param pLayerResult the layer where the features resulting from the
    5696             :  * operation are inserted. Should not be NULL. See above the note
    5697             :  * about the schema.
    5698             :  *
    5699             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5700             :  *
    5701             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5702             :  * reporting progress or NULL.
    5703             :  *
    5704             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5705             :  *
    5706             :  * @return an error code if there was an error or the execution was
    5707             :  * interrupted, OGRERR_NONE otherwise.
    5708             :  *
    5709             :  * @note The first geometry field is always used.
    5710             :  *
    5711             :  * @since OGR 1.10
    5712             :  */
    5713             : 
    5714           3 : OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    5715             :                   OGRLayerH pLayerResult, char **papszOptions,
    5716             :                   GDALProgressFunc pfnProgress, void *pProgressArg)
    5717             : 
    5718             : {
    5719           3 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    5720           3 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    5721           3 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    5722             : 
    5723             :     return OGRLayer::FromHandle(pLayerInput)
    5724           3 :         ->Clip(OGRLayer::FromHandle(pLayerMethod),
    5725             :                OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    5726           3 :                pProgressArg);
    5727             : }
    5728             : 
    5729             : /************************************************************************/
    5730             : /*                              Erase()                                 */
    5731             : /************************************************************************/
    5732             : 
    5733             : /**
    5734             :  * \brief Remove areas that are covered by the method layer.
    5735             :  *
    5736             :  * The result layer contains features whose geometries represent areas
    5737             :  * that are in the input layer but not in the method layer. The
    5738             :  * features in the result layer have attributes from the input
    5739             :  * layer. The schema of the result layer can be set by the user or, if
    5740             :  * it is empty, is initialized to contain all fields in the input
    5741             :  * layer.
    5742             :  *
    5743             :  * \note For best performance use the minimum amount of features in
    5744             :  * the method layer and copy it into a memory layer.
    5745             :  *
    5746             :  * \note This method relies on GEOS support. Do not use unless the
    5747             :  * GEOS support is compiled in.
    5748             :  *
    5749             :  * The recognized list of options is :
    5750             :  * <ul>
    5751             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5752             :  *     feature could not be inserted or a GEOS call failed.
    5753             :  * </li>
    5754             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5755             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5756             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5757             :  * </li>
    5758             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5759             :  *     will be created from the fields of the input layer.
    5760             :  * </li>
    5761             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5762             :  *     will be created from the fields of the method layer.
    5763             :  * </li>
    5764             :  * </ul>
    5765             :  *
    5766             :  * This method is the same as the C function OGR_L_Erase().
    5767             :  *
    5768             :  * @param pLayerMethod the method layer. Should not be NULL.
    5769             :  *
    5770             :  * @param pLayerResult the layer where the features resulting from the
    5771             :  * operation are inserted. Should not be NULL. See above the note
    5772             :  * about the schema.
    5773             :  *
    5774             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5775             :  *
    5776             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5777             :  * reporting progress or NULL.
    5778             :  *
    5779             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5780             :  *
    5781             :  * @return an error code if there was an error or the execution was
    5782             :  * interrupted, OGRERR_NONE otherwise.
    5783             :  *
    5784             :  * @note The first geometry field is always used.
    5785             :  *
    5786             :  * @since OGR 1.10
    5787             :  */
    5788             : 
    5789           6 : OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    5790             :                        char **papszOptions, GDALProgressFunc pfnProgress,
    5791             :                        void *pProgressArg)
    5792             : {
    5793           6 :     OGRErr ret = OGRERR_NONE;
    5794           6 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    5795           6 :     OGRFeatureDefn *poDefnResult = nullptr;
    5796           6 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    5797           6 :     int *mapInput = nullptr;
    5798           6 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    5799           6 :     double progress_counter = 0;
    5800           6 :     double progress_ticker = 0;
    5801             :     const bool bSkipFailures =
    5802           6 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    5803           6 :     const bool bPromoteToMulti = CPLTestBool(
    5804             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    5805             : 
    5806             :     // check for GEOS
    5807           6 :     if (!OGRGeometryFactory::haveGEOS())
    5808             :     {
    5809           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    5810             :                  "OGRLayer::Erase() requires GEOS support");
    5811           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    5812             :     }
    5813             : 
    5814             :     // get resources
    5815           6 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    5816           6 :     if (ret != OGRERR_NONE)
    5817           0 :         goto done;
    5818           6 :     ret = create_field_map(poDefnInput, &mapInput);
    5819           6 :     if (ret != OGRERR_NONE)
    5820           0 :         goto done;
    5821           6 :     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
    5822             :                             nullptr, false, papszOptions);
    5823           6 :     if (ret != OGRERR_NONE)
    5824           0 :         goto done;
    5825           6 :     poDefnResult = pLayerResult->GetLayerDefn();
    5826             : 
    5827          18 :     for (auto &&x : this)
    5828             :     {
    5829             : 
    5830          12 :         if (pfnProgress)
    5831             :         {
    5832           2 :             double p = progress_counter / progress_max;
    5833           2 :             if (p > progress_ticker)
    5834             :             {
    5835           1 :                 if (!pfnProgress(p, "", pProgressArg))
    5836             :                 {
    5837           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5838           0 :                     ret = OGRERR_FAILURE;
    5839           0 :                     goto done;
    5840             :                 }
    5841             :             }
    5842           2 :             progress_counter += 1.0;
    5843             :         }
    5844             : 
    5845             :         // set up the filter on the method layer
    5846          12 :         CPLErrorReset();
    5847             :         OGRGeometry *x_geom =
    5848          12 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    5849          12 :         if (CPLGetLastErrorType() != CE_None)
    5850             :         {
    5851           0 :             if (!bSkipFailures)
    5852             :             {
    5853           0 :                 ret = OGRERR_FAILURE;
    5854           0 :                 goto done;
    5855             :             }
    5856             :             else
    5857             :             {
    5858           0 :                 CPLErrorReset();
    5859           0 :                 ret = OGRERR_NONE;
    5860             :             }
    5861             :         }
    5862          12 :         if (!x_geom)
    5863             :         {
    5864           0 :             continue;
    5865             :         }
    5866             : 
    5867             :         OGRGeometryUniquePtr geom(
    5868             :             x_geom
    5869          12 :                 ->clone());  // this will be the geometry of the result feature
    5870             :         // incrementally erase y from geom
    5871          19 :         for (auto &&y : pLayerMethod)
    5872             :         {
    5873           9 :             OGRGeometry *y_geom = y->GetGeometryRef();
    5874           9 :             if (!y_geom)
    5875           0 :                 continue;
    5876           9 :             CPLErrorReset();
    5877           9 :             OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    5878           9 :             if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    5879             :             {
    5880           0 :                 if (!bSkipFailures)
    5881             :                 {
    5882           0 :                     ret = OGRERR_FAILURE;
    5883           0 :                     goto done;
    5884             :                 }
    5885             :                 else
    5886             :                 {
    5887           0 :                     CPLErrorReset();
    5888           0 :                     ret = OGRERR_NONE;
    5889             :                 }
    5890             :             }
    5891             :             else
    5892             :             {
    5893           9 :                 geom.swap(geom_new);
    5894           9 :                 if (geom->IsEmpty())
    5895             :                 {
    5896           2 :                     break;
    5897             :                 }
    5898             :             }
    5899             :         }
    5900             : 
    5901             :         // add a new feature if there is remaining area
    5902          12 :         if (!geom->IsEmpty())
    5903             :         {
    5904          10 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    5905          10 :             z->SetFieldsFrom(x.get(), mapInput);
    5906          10 :             if (bPromoteToMulti)
    5907           4 :                 geom.reset(promote_to_multi(geom.release()));
    5908          10 :             z->SetGeometryDirectly(geom.release());
    5909          10 :             ret = pLayerResult->CreateFeature(z.get());
    5910          10 :             if (ret != OGRERR_NONE)
    5911             :             {
    5912           0 :                 if (!bSkipFailures)
    5913             :                 {
    5914           0 :                     goto done;
    5915             :                 }
    5916             :                 else
    5917             :                 {
    5918           0 :                     CPLErrorReset();
    5919           0 :                     ret = OGRERR_NONE;
    5920             :                 }
    5921             :             }
    5922             :         }
    5923             :     }
    5924           6 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    5925             :     {
    5926           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5927           0 :         ret = OGRERR_FAILURE;
    5928           0 :         goto done;
    5929             :     }
    5930           6 : done:
    5931             :     // release resources
    5932           6 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    5933           6 :     if (pGeometryMethodFilter)
    5934           0 :         delete pGeometryMethodFilter;
    5935           6 :     if (mapInput)
    5936           5 :         VSIFree(mapInput);
    5937           6 :     return ret;
    5938             : }
    5939             : 
    5940             : /************************************************************************/
    5941             : /*                           OGR_L_Erase()                              */
    5942             : /************************************************************************/
    5943             : 
    5944             : /**
    5945             :  * \brief Remove areas that are covered by the method layer.
    5946             :  *
    5947             :  * The result layer contains features whose geometries represent areas
    5948             :  * that are in the input layer but not in the method layer. The
    5949             :  * features in the result layer have attributes from the input
    5950             :  * layer. The schema of the result layer can be set by the user or, if
    5951             :  * it is empty, is initialized to contain all fields in the input
    5952             :  * layer.
    5953             :  *
    5954             :  * \note For best performance use the minimum amount of features in
    5955             :  * the method layer and copy it into a memory layer.
    5956             :  *
    5957             :  * \note This method relies on GEOS support. Do not use unless the
    5958             :  * GEOS support is compiled in.
    5959             :  *
    5960             :  * The recognized list of options is :
    5961             :  * <ul>
    5962             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5963             :  *     feature could not be inserted or a GEOS call failed.
    5964             :  * </li>
    5965             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5966             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5967             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5968             :  * </li>
    5969             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5970             :  *     will be created from the fields of the input layer.
    5971             :  * </li>
    5972             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5973             :  *     will be created from the fields of the method layer.
    5974             :  * </li>
    5975             :  * </ul>
    5976             :  *
    5977             :  * This function is the same as the C++ method OGRLayer::Erase().
    5978             :  *
    5979             :  * @param pLayerInput the input layer. Should not be NULL.
    5980             :  *
    5981             :  * @param pLayerMethod the method layer. Should not be NULL.
    5982             :  *
    5983             :  * @param pLayerResult the layer where the features resulting from the
    5984             :  * operation are inserted. Should not be NULL. See above the note
    5985             :  * about the schema.
    5986             :  *
    5987             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5988             :  *
    5989             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5990             :  * reporting progress or NULL.
    5991             :  *
    5992             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5993             :  *
    5994             :  * @return an error code if there was an error or the execution was
    5995             :  * interrupted, OGRERR_NONE otherwise.
    5996             :  *
    5997             :  * @note The first geometry field is always used.
    5998             :  *
    5999             :  * @since OGR 1.10
    6000             :  */
    6001             : 
    6002           6 : OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    6003             :                    OGRLayerH pLayerResult, char **papszOptions,
    6004             :                    GDALProgressFunc pfnProgress, void *pProgressArg)
    6005             : 
    6006             : {
    6007           6 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    6008           6 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    6009           6 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    6010             : 
    6011             :     return OGRLayer::FromHandle(pLayerInput)
    6012           6 :         ->Erase(OGRLayer::FromHandle(pLayerMethod),
    6013             :                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    6014           6 :                 pProgressArg);
    6015             : }
    6016             : 
    6017             : /************************************************************************/
    6018             : /*                  OGRLayer::FeatureIterator::Private                  */
    6019             : /************************************************************************/
    6020             : 
    6021             : struct OGRLayer::FeatureIterator::Private
    6022             : {
    6023             :     CPL_DISALLOW_COPY_ASSIGN(Private)
    6024       35954 :     Private() = default;
    6025             : 
    6026             :     OGRFeatureUniquePtr m_poFeature{};
    6027             :     OGRLayer *m_poLayer = nullptr;
    6028             :     bool m_bError = false;
    6029             :     bool m_bEOF = true;
    6030             : };
    6031             : 
    6032             : /************************************************************************/
    6033             : /*                OGRLayer::FeatureIterator::FeatureIterator()          */
    6034             : /************************************************************************/
    6035             : 
    6036       35954 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
    6037       35954 :     : m_poPrivate(new OGRLayer::FeatureIterator::Private())
    6038             : {
    6039       35954 :     m_poPrivate->m_poLayer = poLayer;
    6040       35954 :     if (bStart)
    6041             :     {
    6042       17977 :         if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
    6043             :         {
    6044           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    6045             :                      "Only one feature iterator can be "
    6046             :                      "active at a time");
    6047           1 :             m_poPrivate->m_bError = true;
    6048             :         }
    6049             :         else
    6050             :         {
    6051       17976 :             m_poPrivate->m_poLayer->ResetReading();
    6052       35952 :             m_poPrivate->m_poFeature.reset(
    6053       17976 :                 m_poPrivate->m_poLayer->GetNextFeature());
    6054       17976 :             m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
    6055       17976 :             m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
    6056             :         }
    6057             :     }
    6058       35954 : }
    6059             : 
    6060             : /************************************************************************/
    6061             : /*               ~OGRLayer::FeatureIterator::FeatureIterator()          */
    6062             : /************************************************************************/
    6063             : 
    6064       35954 : OGRLayer::FeatureIterator::~FeatureIterator()
    6065             : {
    6066       35954 :     if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
    6067       35953 :         m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
    6068       35954 : }
    6069             : 
    6070             : /************************************************************************/
    6071             : /*                              operator*()                             */
    6072             : /************************************************************************/
    6073             : 
    6074      154107 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
    6075             : {
    6076      154107 :     return m_poPrivate->m_poFeature;
    6077             : }
    6078             : 
    6079             : /************************************************************************/
    6080             : /*                              operator++()                            */
    6081             : /************************************************************************/
    6082             : 
    6083      153425 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
    6084             : {
    6085      153425 :     m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
    6086      153425 :     m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
    6087      153425 :     return *this;
    6088             : }
    6089             : 
    6090             : /************************************************************************/
    6091             : /*                             operator!=()                             */
    6092             : /************************************************************************/
    6093             : 
    6094      171402 : bool OGRLayer::FeatureIterator::operator!=(
    6095             :     const OGRLayer::FeatureIterator &it) const
    6096             : {
    6097      171402 :     return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
    6098             : }
    6099             : 
    6100             : /************************************************************************/
    6101             : /*                                 begin()                              */
    6102             : /************************************************************************/
    6103             : 
    6104       17977 : OGRLayer::FeatureIterator OGRLayer::begin()
    6105             : {
    6106       17977 :     return {this, true};
    6107             : }
    6108             : 
    6109             : /************************************************************************/
    6110             : /*                                  end()                               */
    6111             : /************************************************************************/
    6112             : 
    6113       17977 : OGRLayer::FeatureIterator OGRLayer::end()
    6114             : {
    6115       17977 :     return {this, false};
    6116             : }
    6117             : 
    6118             : /************************************************************************/
    6119             : /*                     OGRLayer::GetGeometryTypes()                     */
    6120             : /************************************************************************/
    6121             : 
    6122             : /** \brief Get actual geometry types found in features.
    6123             :  *
    6124             :  * This method iterates over features to retrieve their geometry types. This
    6125             :  * is mostly useful for layers that report a wkbUnknown geometry type with
    6126             :  * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
    6127             :  *
    6128             :  * By default this method returns an array of nEntryCount entries with each
    6129             :  * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
    6130             :  * number of features (in OGRGeometryTypeCounter::nCount).
    6131             :  * Features without geometries are reported as eGeomType == wkbNone.
    6132             :  *
    6133             :  * The nFlagsGGT parameter can be a combination (with binary or operator) of the
    6134             :  * following hints:
    6135             :  * <ul>
    6136             :  * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
    6137             :  * matter, not the number of features per geometry type. Consequently the value
    6138             :  * of OGRGeometryTypeCounter::nCount should be ignored.</li>
    6139             :  * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
    6140             :  * iterating over features as soon as 2 different geometry types (not counting
    6141             :  * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
    6142             :  * should be ignored (zero might be systematically reported by some
    6143             :  * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
    6144             :  * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
    6145             :  * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
    6146             :  * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
    6147             :  * geometries.</li>
    6148             :  * </ul>
    6149             :  *
    6150             :  * If the layer has no features, a non-NULL returned array with nEntryCount == 0
    6151             :  * will be returned.
    6152             :  *
    6153             :  * Spatial and/or attribute filters will be taken into account.
    6154             :  *
    6155             :  * This method will error out on a layer without geometry fields
    6156             :  * (GetGeomType() == wkbNone).
    6157             :  *
    6158             :  * A cancellation callback may be provided. The progress percentage it is called
    6159             :  * with is not relevant. The callback should return TRUE if processing should go
    6160             :  * on, or FALSE if it should be interrupted.
    6161             :  *
    6162             :  * @param iGeomField Geometry field index.
    6163             :  * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
    6164             :  *                  OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
    6165             :  * @param[out] nEntryCountOut Number of entries in the returned array.
    6166             :  * @param pfnProgress Cancellation callback. May be NULL.
    6167             :  * @param pProgressData User data for the cancellation callback. May be NULL.
    6168             :  * @return an array of nEntryCount that must be freed with CPLFree(),
    6169             :  *         or NULL in case of error
    6170             :  * @since GDAL 3.6
    6171             :  */
    6172             : OGRGeometryTypeCounter *
    6173          12 : OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
    6174             :                            GDALProgressFunc pfnProgress, void *pProgressData)
    6175             : {
    6176          12 :     OGRFeatureDefn *poDefn = GetLayerDefn();
    6177          12 :     const int nGeomFieldCount = poDefn->GetGeomFieldCount();
    6178          12 :     if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
    6179             :     {
    6180           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
    6181           1 :         nEntryCountOut = 0;
    6182           1 :         return nullptr;
    6183             :     }
    6184             : 
    6185             :     // Ignore all fields but the geometry one of interest
    6186          22 :     CPLStringList aosIgnoredFieldsRestore;
    6187          22 :     CPLStringList aosIgnoredFields;
    6188          11 :     const int nFieldCount = poDefn->GetFieldCount();
    6189          33 :     for (int iField = 0; iField < nFieldCount; iField++)
    6190             :     {
    6191          22 :         const auto poFieldDefn = poDefn->GetFieldDefn(iField);
    6192          22 :         const char *pszName = poFieldDefn->GetNameRef();
    6193          22 :         if (poFieldDefn->IsIgnored())
    6194          10 :             aosIgnoredFieldsRestore.AddString(pszName);
    6195          22 :         if (iField != iGeomField)
    6196          11 :             aosIgnoredFields.AddString(pszName);
    6197             :     }
    6198          33 :     for (int iField = 0; iField < nGeomFieldCount; iField++)
    6199             :     {
    6200          22 :         const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
    6201          22 :         const char *pszName = poFieldDefn->GetNameRef();
    6202          22 :         if (poFieldDefn->IsIgnored())
    6203          10 :             aosIgnoredFieldsRestore.AddString(pszName);
    6204          22 :         if (iField != iGeomField)
    6205          11 :             aosIgnoredFields.AddString(pszName);
    6206             :     }
    6207          11 :     if (poDefn->IsStyleIgnored())
    6208           0 :         aosIgnoredFieldsRestore.AddString("OGR_STYLE");
    6209          11 :     aosIgnoredFields.AddString("OGR_STYLE");
    6210          11 :     SetIgnoredFields(aosIgnoredFields.List());
    6211             : 
    6212             :     // Iterate over features
    6213          22 :     std::map<OGRwkbGeometryType, int64_t> oMapCount;
    6214          22 :     std::set<OGRwkbGeometryType> oSetNotNull;
    6215          11 :     const bool bGeomCollectionZTInZ =
    6216          11 :         (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
    6217          11 :     const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
    6218          11 :     if (pfnProgress == GDALDummyProgress)
    6219           0 :         pfnProgress = nullptr;
    6220          11 :     bool bInterrupted = false;
    6221          47 :     for (auto &&poFeature : *this)
    6222             :     {
    6223          36 :         const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
    6224          36 :         if (poGeom == nullptr)
    6225             :         {
    6226          18 :             ++oMapCount[wkbNone];
    6227             :         }
    6228             :         else
    6229             :         {
    6230          18 :             auto eGeomType = poGeom->getGeometryType();
    6231          18 :             if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
    6232             :             {
    6233           1 :                 const auto poGC = poGeom->toGeometryCollection();
    6234           1 :                 if (poGC->getNumGeometries() > 0)
    6235             :                 {
    6236             :                     auto eSubGeomType =
    6237           1 :                         poGC->getGeometryRef(0)->getGeometryType();
    6238           1 :                     if (eSubGeomType == wkbTINZ)
    6239           1 :                         eGeomType = wkbTINZ;
    6240             :                 }
    6241             :             }
    6242          18 :             ++oMapCount[eGeomType];
    6243          18 :             if (bStopIfMixed)
    6244             :             {
    6245           4 :                 oSetNotNull.insert(eGeomType);
    6246           4 :                 if (oSetNotNull.size() == 2)
    6247           2 :                     break;
    6248             :             }
    6249             :         }
    6250          34 :         if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
    6251             :         {
    6252           1 :             bInterrupted = true;
    6253           1 :             break;
    6254             :         }
    6255             :     }
    6256             : 
    6257             :     // Restore ignore fields state
    6258          11 :     SetIgnoredFields(aosIgnoredFieldsRestore.List());
    6259             : 
    6260          11 :     if (bInterrupted)
    6261             :     {
    6262           1 :         nEntryCountOut = 0;
    6263           1 :         return nullptr;
    6264             :     }
    6265             : 
    6266             :     // Format result
    6267          10 :     nEntryCountOut = static_cast<int>(oMapCount.size());
    6268             :     OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
    6269          10 :         CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
    6270          10 :     int i = 0;
    6271          37 :     for (const auto &oIter : oMapCount)
    6272             :     {
    6273          27 :         pasRet[i].eGeomType = oIter.first;
    6274          27 :         pasRet[i].nCount = oIter.second;
    6275          27 :         ++i;
    6276             :     }
    6277          10 :     return pasRet;
    6278             : }
    6279             : 
    6280             : /************************************************************************/
    6281             : /*                      OGR_L_GetGeometryTypes()                        */
    6282             : /************************************************************************/
    6283             : 
    6284             : /** \brief Get actual geometry types found in features.
    6285             :  *
    6286             :  * See OGRLayer::GetGeometryTypes() for details.
    6287             :  *
    6288             :  * @param hLayer Layer.
    6289             :  * @param iGeomField Geometry field index.
    6290             :  * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
    6291             :  *               OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
    6292             :  * @param[out] pnEntryCount Pointer to the number of entries in the returned
    6293             :  *                          array. Must not be NULL.
    6294             :  * @param pfnProgress Cancellation callback. May be NULL.
    6295             :  * @param pProgressData User data for the cancellation callback. May be NULL.
    6296             :  * @return an array of *pnEntryCount that must be freed with CPLFree(),
    6297             :  *         or NULL in case of error
    6298             :  * @since GDAL 3.6
    6299             :  */
    6300          54 : OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
    6301             :                                                int nFlags, int *pnEntryCount,
    6302             :                                                GDALProgressFunc pfnProgress,
    6303             :                                                void *pProgressData)
    6304             : {
    6305          54 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
    6306          54 :     VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
    6307             : 
    6308         108 :     return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
    6309          54 :         iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
    6310             : }
    6311             : 
    6312             : /************************************************************************/
    6313             : /*                    OGRLayer::GetSupportedSRSList()                   */
    6314             : /************************************************************************/
    6315             : 
    6316             : /** \brief Get the list of SRS supported.
    6317             :  *
    6318             :  * The base implementation of this method will return an empty list. Some
    6319             :  * drivers (OAPIF, WFS) may return a non-empty list.
    6320             :  *
    6321             :  * One of the SRS returned may be passed to SetActiveSRS() to change the
    6322             :  * active SRS.
    6323             :  *
    6324             :  * @param iGeomField Geometry field index.
    6325             :  * @return list of supported SRS.
    6326             :  * @since GDAL 3.7
    6327             :  */
    6328             : const OGRLayer::GetSupportedSRSListRetType &
    6329         175 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
    6330             : {
    6331         175 :     static OGRLayer::GetSupportedSRSListRetType empty;
    6332         175 :     return empty;
    6333             : }
    6334             : 
    6335             : /************************************************************************/
    6336             : /*                    OGR_L_GetSupportedSRSList()                       */
    6337             : /************************************************************************/
    6338             : 
    6339             : /** \brief Get the list of SRS supported.
    6340             :  *
    6341             :  * The base implementation of this method will return an empty list. Some
    6342             :  * drivers (OAPIF, WFS) may return a non-empty list.
    6343             :  *
    6344             :  * One of the SRS returned may be passed to SetActiveSRS() to change the
    6345             :  * active SRS.
    6346             :  *
    6347             :  * @param hLayer Layer.
    6348             :  * @param iGeomField Geometry field index.
    6349             :  * @param[out] pnCount Number of values in returned array. Must not be null.
    6350             :  * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
    6351             :  * nullptr
    6352             :  * @since GDAL 3.7
    6353             :  */
    6354           4 : OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
    6355             :                                                 int iGeomField, int *pnCount)
    6356             : {
    6357           4 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
    6358           4 :     VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
    6359             : 
    6360             :     const auto &srsList =
    6361           4 :         OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
    6362           4 :     *pnCount = static_cast<int>(srsList.size());
    6363           4 :     if (srsList.empty())
    6364             :     {
    6365           2 :         return nullptr;
    6366             :     }
    6367             :     OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
    6368           2 :         CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
    6369           2 :     size_t i = 0;
    6370           7 :     for (const auto &poSRS : srsList)
    6371             :     {
    6372           5 :         poSRS->Reference();
    6373           5 :         pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
    6374           5 :         ++i;
    6375             :     }
    6376           2 :     pahRet[i] = nullptr;
    6377           2 :     return pahRet;
    6378             : }
    6379             : 
    6380             : /************************************************************************/
    6381             : /*                       OGRLayer::SetActiveSRS()                       */
    6382             : /************************************************************************/
    6383             : 
    6384             : /** \brief Change the active SRS.
    6385             :  *
    6386             :  * The passed SRS must be in the list returned by GetSupportedSRSList()
    6387             :  * (the actual pointer may be different, but should be tested as identical
    6388             :  * with OGRSpatialReference::IsSame()).
    6389             :  *
    6390             :  * Changing the active SRS affects:
    6391             :  * <ul>
    6392             :  * <li>the SRS in which geometries of returned features are expressed,</li>
    6393             :  * <li>the SRS in which geometries of passed features (CreateFeature(),
    6394             :  * SetFeature()) are expressed,</li>
    6395             :  * <li>the SRS returned by GetSpatialRef() and
    6396             :  * GetGeomFieldDefn()->GetSpatialRef(),</li>
    6397             :  * <li>the SRS used to interpret SetSpatialFilter() values.</li>
    6398             :  * </ul>
    6399             :  * This also resets feature reading and the spatial filter.
    6400             :  * Note however that this does not modify the storage SRS of the features of
    6401             :  * geometries. Said otherwise, this setting is volatile and has no persistent
    6402             :  * effects after dataset reopening.
    6403             :  *
    6404             :  * @param iGeomField Geometry field index.
    6405             :  * @param poSRS SRS to use
    6406             :  * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
    6407             :  *         the passed SRS is not in GetSupportedSRSList()
    6408             :  * @since GDAL 3.7
    6409             :  */
    6410           1 : OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
    6411             :                               CPL_UNUSED const OGRSpatialReference *poSRS)
    6412             : {
    6413           1 :     return OGRERR_FAILURE;
    6414             : }
    6415             : 
    6416             : /************************************************************************/
    6417             : /*                         OGR_L_SetActiveSRS()                         */
    6418             : /************************************************************************/
    6419             : 
    6420             : /** \brief Change the active SRS.
    6421             :  *
    6422             :  * The passed SRS must be in the list returned by GetSupportedSRSList()
    6423             :  * (the actual pointer may be different, but should be tested as identical
    6424             :  * with OGRSpatialReference::IsSame()).
    6425             :  *
    6426             :  * Changing the active SRS affects:
    6427             :  * <ul>
    6428             :  * <li>the SRS in which geometries of returned features are expressed,</li>
    6429             :  * <li>the SRS in which geometries of passed features (CreateFeature(),
    6430             :  * SetFeature()) are expressed,</li>
    6431             :  * <li>the SRS returned by GetSpatialRef() and
    6432             :  * GetGeomFieldDefn()->GetSpatialRef(),</li>
    6433             :  * <li>the SRS used to interpret SetSpatialFilter() values.</li>
    6434             :  * </ul>
    6435             :  * This also resets feature reading and the spatial filter.
    6436             :  * Note however that this does not modify the storage SRS of the features of
    6437             :  * geometries. Said otherwise, this setting is volatile and has no persistent
    6438             :  * effects after dataset reopening.
    6439             :  *
    6440             :  * @param hLayer Layer.
    6441             :  * @param iGeomField Geometry field index.
    6442             :  * @param hSRS SRS to use
    6443             :  * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
    6444             :  *         the passed SRS is not in GetSupportedSRSList().
    6445             :  * @since GDAL 3.7
    6446             :  */
    6447           9 : OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
    6448             :                           OGRSpatialReferenceH hSRS)
    6449             : {
    6450           9 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
    6451          18 :     return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
    6452           9 :         iGeomField, OGRSpatialReference::FromHandle(hSRS));
    6453             : }
    6454             : 
    6455             : /************************************************************************/
    6456             : /*                             GetDataset()                             */
    6457             : /************************************************************************/
    6458             : 
    6459             : /** Return the dataset associated with this layer.
    6460             :  *
    6461             :  * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
    6462             :  * have CreateLayer() capability. It may not be implemented in read-only
    6463             :  * drivers or out-of-tree drivers.
    6464             :  *
    6465             :  * It is currently only used by the GetRecordBatchSchema()
    6466             :  * method to retrieve the field domain associated with a field, to fill the
    6467             :  * dictionary field of a struct ArrowSchema.
    6468             :  * It is also used by CreateFieldFromArrowSchema() to determine which field
    6469             :  * types and subtypes are supported by the layer, by inspecting the driver
    6470             :  * metadata, and potentially use fallback types when needed.
    6471             :  *
    6472             :  * This method is the same as the C function OGR_L_GetDataset().
    6473             :  *
    6474             :  * @return dataset, or nullptr when unknown.
    6475             :  * @since GDAL 3.6
    6476             :  */
    6477           1 : GDALDataset *OGRLayer::GetDataset()
    6478             : {
    6479           1 :     return nullptr;
    6480             : }
    6481             : 
    6482             : /************************************************************************/
    6483             : /*                          OGR_L_GetDataset()                          */
    6484             : /************************************************************************/
    6485             : 
    6486             : /** Return the dataset associated with this layer.
    6487             :  *
    6488             :  * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
    6489             :  * have CreateLayer() capability. It may not be implemented in read-only
    6490             :  * drivers or out-of-tree drivers.
    6491             :  *
    6492             :  * It is currently only used by the GetRecordBatchSchema()
    6493             :  * method to retrieve the field domain associated with a field, to fill the
    6494             :  * dictionary field of a struct ArrowSchema.
    6495             :  * It is also used by CreateFieldFromArrowSchema() to determine which field
    6496             :  * types and subtypes are supported by the layer, by inspecting the driver
    6497             :  * metadata, and potentially use fallback types when needed.
    6498             :  *
    6499             :  * This function is the same as the C++ method OGRLayer::GetDataset().
    6500             :  *
    6501             :  * @return dataset, or nullptr when unknown.
    6502             :  * @since GDAL 3.9
    6503             :  */
    6504         264 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
    6505             : {
    6506         264 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
    6507         264 :     return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
    6508             : }

Generated by: LCOV version 1.14