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

Generated by: LCOV version 1.14