LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1620 2068 78.3 %
Date: 2026-05-08 18:52:02 Functions: 132 152 86.8 %

          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       76773 : OGRLayer::OGRLayer()
      35       76773 :     : m_poPrivate(new Private()), m_bFilterIsEnvelope(FALSE),
      36             :       m_poFilterGeom(nullptr), m_pPreparedFilterGeom(nullptr),
      37             :       m_sFilterEnvelope{}, m_iGeomFieldFilter(0), m_poStyleTable(nullptr),
      38             :       m_poAttrQuery(nullptr), m_pszAttrQueryString(nullptr),
      39      153546 :       m_poAttrIndex(nullptr), m_nRefCount(0), m_nFeaturesRead(0)
      40             : {
      41       76773 : }
      42             : 
      43             : /************************************************************************/
      44             : /*                             ~OGRLayer()                              */
      45             : /************************************************************************/
      46             : 
      47       76753 : OGRLayer::~OGRLayer()
      48             : 
      49             : {
      50       76753 :     if (m_poStyleTable)
      51             :     {
      52          11 :         delete m_poStyleTable;
      53          11 :         m_poStyleTable = nullptr;
      54             :     }
      55             : 
      56       76753 :     if (m_poAttrIndex != nullptr)
      57             :     {
      58         174 :         delete m_poAttrIndex;
      59         174 :         m_poAttrIndex = nullptr;
      60             :     }
      61             : 
      62       76753 :     if (m_poAttrQuery != nullptr)
      63             :     {
      64         656 :         delete m_poAttrQuery;
      65         656 :         m_poAttrQuery = nullptr;
      66             :     }
      67             : 
      68       76753 :     CPLFree(m_pszAttrQueryString);
      69             : 
      70       76753 :     if (m_poFilterGeom)
      71             :     {
      72        1079 :         delete m_poFilterGeom;
      73        1079 :         m_poFilterGeom = nullptr;
      74             :     }
      75             : 
      76       76753 :     if (m_pPreparedFilterGeom != nullptr)
      77             :     {
      78        1079 :         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
      79        1079 :         m_pPreparedFilterGeom = nullptr;
      80             :     }
      81             : 
      82       76753 :     if (m_poSharedArrowArrayStreamPrivateData != nullptr)
      83             :     {
      84         758 :         m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
      85             :     }
      86       76753 : }
      87             : 
      88             : /************************************************************************/
      89             : /*                             Reference()                              */
      90             : /************************************************************************/
      91             : 
      92             : /**
      93             : \brief Increment layer reference count.
      94             : 
      95             : This method is the same as the C function OGR_L_Reference().
      96             : 
      97             : @return the reference count after incrementing.
      98             : */
      99           0 : int OGRLayer::Reference()
     100             : 
     101             : {
     102           0 :     return ++m_nRefCount;
     103             : }
     104             : 
     105             : /************************************************************************/
     106             : /*                          OGR_L_Reference()                           */
     107             : /************************************************************************/
     108             : 
     109           0 : int OGR_L_Reference(OGRLayerH hLayer)
     110             : 
     111             : {
     112           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_Reference", 0);
     113             : 
     114           0 :     return OGRLayer::FromHandle(hLayer)->Reference();
     115             : }
     116             : 
     117             : /************************************************************************/
     118             : /*                            Dereference()                             */
     119             : /************************************************************************/
     120             : 
     121             : /**
     122             : \brief Decrement layer reference count.
     123             : 
     124             : This method is the same as the C function OGR_L_Dereference().
     125             : 
     126             : @return the reference count after decrementing.
     127             : */
     128             : 
     129           0 : int OGRLayer::Dereference()
     130             : 
     131             : {
     132           0 :     return --m_nRefCount;
     133             : }
     134             : 
     135             : /************************************************************************/
     136             : /*                         OGR_L_Dereference()                          */
     137             : /************************************************************************/
     138             : 
     139           0 : int OGR_L_Dereference(OGRLayerH hLayer)
     140             : 
     141             : {
     142           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_Dereference", 0);
     143             : 
     144           0 :     return OGRLayer::FromHandle(hLayer)->Dereference();
     145             : }
     146             : 
     147             : /************************************************************************/
     148             : /*                            GetRefCount()                             */
     149             : /************************************************************************/
     150             : 
     151             : /**
     152             : \brief Fetch reference count.
     153             : 
     154             : This method is the same as the C function OGR_L_GetRefCount().
     155             : 
     156             : @return the current reference count for the layer object itself.
     157             : */
     158             : 
     159           0 : int OGRLayer::GetRefCount() const
     160             : 
     161             : {
     162           0 :     return m_nRefCount;
     163             : }
     164             : 
     165             : /************************************************************************/
     166             : /*                         OGR_L_GetRefCount()                          */
     167             : /************************************************************************/
     168             : 
     169           0 : int OGR_L_GetRefCount(OGRLayerH hLayer)
     170             : 
     171             : {
     172           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetRefCount", 0);
     173             : 
     174           0 :     return OGRLayer::FromHandle(hLayer)->GetRefCount();
     175             : }
     176             : 
     177             : /************************************************************************/
     178             : /*                          GetFeatureCount()                           */
     179             : /************************************************************************/
     180             : 
     181             : /**
     182             :  \brief Fetch the feature count in this layer.
     183             : 
     184             :  Returns the number of features in the layer.  For dynamic databases the
     185             :  count may not be exact.  If bForce is FALSE, and it would be expensive
     186             :  to establish the feature count a value of -1 may be returned indicating
     187             :  that the count isn't know.  If bForce is TRUE some implementations will
     188             :  actually scan the entire layer once to count objects.
     189             : 
     190             :  The returned count takes the spatial filter into account.
     191             : 
     192             :  Note that some implementations of this method may alter the read cursor
     193             :  of the layer.
     194             : 
     195             :  This method is the same as the C function OGR_L_GetFeatureCount().
     196             : 
     197             : 
     198             :  @param bForce Flag indicating whether the count should be computed even
     199             :  if it is expensive.
     200             : 
     201             :  @return feature count, -1 if count not known.
     202             : */
     203             : 
     204       14631 : GIntBig OGRLayer::GetFeatureCount(int bForce)
     205             : 
     206             : {
     207       14631 :     if (!bForce)
     208           1 :         return -1;
     209             : 
     210       14630 :     GIntBig nFeatureCount = 0;
     211       57305 :     for (auto &&poFeature : *this)
     212             :     {
     213       42675 :         CPL_IGNORE_RET_VAL(poFeature.get());
     214       42675 :         nFeatureCount++;
     215             :     }
     216       14630 :     ResetReading();
     217             : 
     218       14630 :     return nFeatureCount;
     219             : }
     220             : 
     221             : /************************************************************************/
     222             : /*                       OGR_L_GetFeatureCount()                        */
     223             : /************************************************************************/
     224             : 
     225             : /**
     226             :  \brief Fetch the feature count in this layer.
     227             : 
     228             :  Returns the number of features in the layer.  For dynamic databases the
     229             :  count may not be exact.  If bForce is FALSE, and it would be expensive
     230             :  to establish the feature count a value of -1 may be returned indicating
     231             :  that the count isn't know.  If bForce is TRUE some implementations will
     232             :  actually scan the entire layer once to count objects.
     233             : 
     234             :  The returned count takes the spatial filter into account.
     235             : 
     236             :  Note that some implementations of this method may alter the read cursor
     237             :  of the layer.
     238             : 
     239             :  This function is the same as the CPP OGRLayer::GetFeatureCount().
     240             : 
     241             : 
     242             :  @param hLayer handle to the layer that owned the features.
     243             :  @param bForce Flag indicating whether the count should be computed even
     244             :  if it is expensive.
     245             : 
     246             :  @return feature count, -1 if count not known.
     247             : */
     248             : 
     249       37442 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
     250             : 
     251             : {
     252       37442 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
     253             : 
     254             : #ifdef OGRAPISPY_ENABLED
     255       37442 :     if (bOGRAPISpyEnabled)
     256           2 :         OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
     257             : #endif
     258             : 
     259       37442 :     return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
     260             : }
     261             : 
     262             : /************************************************************************/
     263             : /*                             GetExtent()                              */
     264             : /************************************************************************/
     265             : 
     266             : /**
     267             :  \brief Fetch the extent of this layer.
     268             : 
     269             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     270             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     271             :  will be returned indicating that the extent isn't know.  If bForce is
     272             :  TRUE then some implementations will actually scan the entire layer once
     273             :  to compute the MBR of all the features in the layer.
     274             : 
     275             :  Depending on the drivers, the returned extent may or may not take the
     276             :  spatial filter into account.  So it is safer to call GetExtent() without
     277             :  setting a spatial filter.
     278             : 
     279             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     280             :  no meaningful extents could be collected.
     281             : 
     282             :  Note that some implementations of this method may alter the read cursor
     283             :  of the layer.
     284             : 
     285             :  This method is the same as the C function OGR_L_GetExtent().
     286             : 
     287             :  @param psExtent the structure in which the extent value will be returned.
     288             :  @param bForce Flag indicating whether the extent should be computed even
     289             :  if it is expensive.
     290             : 
     291             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     292             : */
     293             : 
     294       15464 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
     295             : {
     296       15464 :     return GetExtent(0, psExtent, bForce);
     297             : }
     298             : 
     299             : /**
     300             :  \brief Fetch the extent of this layer, on the specified geometry field.
     301             : 
     302             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     303             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     304             :  will be returned indicating that the extent isn't know.  If bForce is
     305             :  TRUE then some implementations will actually scan the entire layer once
     306             :  to compute the MBR of all the features in the layer.
     307             : 
     308             :  Depending on the drivers, the returned extent may or may not take the
     309             :  spatial filter into account.  So it is safer to call GetExtent() without
     310             :  setting a spatial filter.
     311             : 
     312             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     313             :  no meaningful extents could be collected.
     314             : 
     315             :  Note that some implementations of this method may alter the read cursor
     316             :  of the layer.
     317             : 
     318             :  This method is the same as the C function OGR_L_GetExtentEx().
     319             : 
     320             :  @param iGeomField the index of the geometry field on which to compute the extent.
     321             :  @param psExtent the structure in which the extent value will be returned.
     322             :  @param bForce Flag indicating whether the extent should be computed even
     323             :  if it is expensive.
     324             : 
     325             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     326             : 
     327             : */
     328             : 
     329       17831 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
     330             : {
     331       17831 :     psExtent->MinX = 0.0;
     332       17831 :     psExtent->MaxX = 0.0;
     333       17831 :     psExtent->MinY = 0.0;
     334       17831 :     psExtent->MaxY = 0.0;
     335             : 
     336             :     /* -------------------------------------------------------------------- */
     337             :     /*      If this layer has a none geometry type, then we can             */
     338             :     /*      reasonably assume there are not extents available.              */
     339             :     /* -------------------------------------------------------------------- */
     340       34782 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
     341       16951 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
     342             :     {
     343         880 :         if (iGeomField != 0)
     344             :         {
     345         710 :             CPLError(CE_Failure, CPLE_AppDefined,
     346             :                      "Invalid geometry field index : %d", iGeomField);
     347             :         }
     348         880 :         return OGRERR_FAILURE;
     349             :     }
     350             : 
     351       16951 :     return IGetExtent(iGeomField, psExtent, bForce);
     352             : }
     353             : 
     354             : /************************************************************************/
     355             : /*                             IGetExtent()                             */
     356             : /************************************************************************/
     357             : 
     358             : /**
     359             :  \brief Fetch the extent of this layer, on the specified geometry field.
     360             : 
     361             :  Virtual method implemented by drivers since 3.11. In previous versions,
     362             :  GetExtent() itself was the virtual method.
     363             : 
     364             :  Driver implementations, when wanting to call the base method, must take
     365             :  care of calling OGRLayer::IGetExtent() (and note the public method without
     366             :  the leading I).
     367             : 
     368             :  @param iGeomField 0-based index of the geometry field to consider.
     369             :  @param psExtent the computed extent of the layer.
     370             :  @param bForce if TRUE, the extent will be computed even if all the
     371             :         layer features have to be fetched.
     372             :  @return OGRERR_NONE on success or an error code in case of failure.
     373             :  @since GDAL 3.11
     374             : */
     375             : 
     376         543 : OGRErr OGRLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
     377             : 
     378             : {
     379             :     /* -------------------------------------------------------------------- */
     380             :     /*      If not forced, we should avoid having to scan all the           */
     381             :     /*      features and just return a failure.                             */
     382             :     /* -------------------------------------------------------------------- */
     383         543 :     if (!bForce)
     384           2 :         return OGRERR_FAILURE;
     385             : 
     386             :     /* -------------------------------------------------------------------- */
     387             :     /*      OK, we hate to do this, but go ahead and read through all       */
     388             :     /*      the features to collect geometries and build extents.           */
     389             :     /* -------------------------------------------------------------------- */
     390         541 :     OGREnvelope oEnv;
     391         541 :     bool bExtentSet = false;
     392             : 
     393       10107 :     for (auto &&poFeature : *this)
     394             :     {
     395        9566 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     396        9566 :         if (poGeom == nullptr || poGeom->IsEmpty())
     397             :         {
     398             :             /* Do nothing */
     399             :         }
     400        9263 :         else if (!bExtentSet)
     401             :         {
     402         486 :             poGeom->getEnvelope(psExtent);
     403         972 :             if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
     404         486 :                   std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
     405             :             {
     406         486 :                 bExtentSet = true;
     407             :             }
     408             :         }
     409             :         else
     410             :         {
     411        8777 :             poGeom->getEnvelope(&oEnv);
     412        8777 :             if (oEnv.MinX < psExtent->MinX)
     413         345 :                 psExtent->MinX = oEnv.MinX;
     414        8777 :             if (oEnv.MinY < psExtent->MinY)
     415         389 :                 psExtent->MinY = oEnv.MinY;
     416        8777 :             if (oEnv.MaxX > psExtent->MaxX)
     417         960 :                 psExtent->MaxX = oEnv.MaxX;
     418        8777 :             if (oEnv.MaxY > psExtent->MaxY)
     419         949 :                 psExtent->MaxY = oEnv.MaxY;
     420             :         }
     421             :     }
     422         541 :     ResetReading();
     423             : 
     424         541 :     return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
     425             : }
     426             : 
     427             : /************************************************************************/
     428             : /*                          OGR_L_GetExtent()                           */
     429             : /************************************************************************/
     430             : 
     431             : /**
     432             :  \brief Fetch the extent of this layer.
     433             : 
     434             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     435             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     436             :  will be returned indicating that the extent isn't know.  If bForce is
     437             :  TRUE then some implementations will actually scan the entire layer once
     438             :  to compute the MBR of all the features in the layer.
     439             : 
     440             :  Depending on the drivers, the returned extent may or may not take the
     441             :  spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
     442             :  setting a spatial filter.
     443             : 
     444             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     445             :  no meaningful extents could be collected.
     446             : 
     447             :  Note that some implementations of this method may alter the read cursor
     448             :  of the layer.
     449             : 
     450             :  This function is the same as the C++ method OGRLayer::GetExtent().
     451             : 
     452             :  @param hLayer handle to the layer from which to get extent.
     453             :  @param psExtent the structure in which the extent value will be returned.
     454             :  @param bForce Flag indicating whether the extent should be computed even
     455             :  if it is expensive.
     456             : 
     457             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     458             : 
     459             : */
     460             : 
     461          43 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
     462             : 
     463             : {
     464          43 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
     465             : 
     466             : #ifdef OGRAPISPY_ENABLED
     467          43 :     if (bOGRAPISpyEnabled)
     468           0 :         OGRAPISpy_L_GetExtent(hLayer, bForce);
     469             : #endif
     470             : 
     471          43 :     return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
     472          43 :                                                    bForce != FALSE);
     473             : }
     474             : 
     475             : /************************************************************************/
     476             : /*                         OGR_L_GetExtentEx()                          */
     477             : /************************************************************************/
     478             : 
     479             : /**
     480             :  \brief Fetch the extent of this layer, on the specified geometry field.
     481             : 
     482             :  Returns the extent (MBR) of the data in the layer.  If bForce is FALSE,
     483             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     484             :  will be returned indicating that the extent isn't know.  If bForce is
     485             :  TRUE then some implementations will actually scan the entire layer once
     486             :  to compute the MBR of all the features in the layer.
     487             : 
     488             :  Depending on the drivers, the returned extent may or may not take the
     489             :  spatial filter into account.  So it is safer to call OGR_L_GetExtent() without
     490             :  setting a spatial filter.
     491             : 
     492             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     493             :  no meaningful extents could be collected.
     494             : 
     495             :  Note that some implementations of this method may alter the read cursor
     496             :  of the layer.
     497             : 
     498             :  This function is the same as the C++ method OGRLayer::GetExtent().
     499             : 
     500             :  @param hLayer handle to the layer from which to get extent.
     501             :  @param iGeomField the index of the geometry field on which to compute the extent.
     502             :  @param psExtent the structure in which the extent value will be returned.
     503             :  @param bForce Flag indicating whether the extent should be computed even
     504             :  if it is expensive.
     505             : 
     506             :  @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
     507             : 
     508             : */
     509         380 : OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
     510             :                          OGREnvelope *psExtent, int bForce)
     511             : 
     512             : {
     513         380 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
     514             : 
     515             : #ifdef OGRAPISPY_ENABLED
     516         380 :     if (bOGRAPISpyEnabled)
     517           4 :         OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
     518             : #endif
     519             : 
     520         380 :     return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
     521         380 :                                                    bForce != FALSE);
     522             : }
     523             : 
     524             : /************************************************************************/
     525             : /*                            GetExtent3D()                             */
     526             : /************************************************************************/
     527             : 
     528             : /**
     529             :  \brief Fetch the 3D extent of this layer, on the specified geometry field.
     530             : 
     531             :  Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
     532             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     533             :  will be returned indicating that the extent isn't know.  If bForce is
     534             :  TRUE then some implementations will actually scan the entire layer once
     535             :  to compute the MBR of all the features in the layer.
     536             : 
     537             :  (Contrary to GetExtent() 2D), the returned extent will always take into
     538             :  account the attribute and spatial filters that may be installed.
     539             : 
     540             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     541             :  no meaningful extents could be collected.
     542             : 
     543             :  For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
     544             :  fields will be respectively set to +Infinity and -Infinity.
     545             : 
     546             :  Note that some implementations of this method may alter the read cursor
     547             :  of the layer.
     548             : 
     549             :  This function is the same as the C function OGR_L_GetExtent3D().
     550             : 
     551             :  @param iGeomField 0-based index of the geometry field to consider.
     552             :  @param psExtent3D the computed 3D extent of the layer.
     553             :  @param bForce if TRUE, the extent will be computed even if all the
     554             :         layer features have to be fetched.
     555             :  @return OGRERR_NONE on success or an error code in case of failure.
     556             :  @since GDAL 3.9
     557             : */
     558             : 
     559          68 : OGRErr OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
     560             :                              bool bForce)
     561             : 
     562             : {
     563          68 :     psExtent3D->MinX = 0.0;
     564          68 :     psExtent3D->MaxX = 0.0;
     565          68 :     psExtent3D->MinY = 0.0;
     566          68 :     psExtent3D->MaxY = 0.0;
     567          68 :     psExtent3D->MinZ = std::numeric_limits<double>::infinity();
     568          68 :     psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
     569             : 
     570             :     /* -------------------------------------------------------------------- */
     571             :     /*      If this layer has a none geometry type, then we can             */
     572             :     /*      reasonably assume there are not extents available.              */
     573             :     /* -------------------------------------------------------------------- */
     574         135 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
     575          67 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
     576             :     {
     577           1 :         if (iGeomField != 0)
     578             :         {
     579           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     580             :                      "Invalid geometry field index : %d", iGeomField);
     581             :         }
     582           1 :         return OGRERR_FAILURE;
     583             :     }
     584             : 
     585          67 :     return IGetExtent3D(iGeomField, psExtent3D, bForce);
     586             : }
     587             : 
     588             : /************************************************************************/
     589             : /*                            IGetExtent3D()                            */
     590             : /************************************************************************/
     591             : 
     592             : /**
     593             :  \brief Fetch the 3D extent of this layer, on the specified geometry field.
     594             : 
     595             :  See GetExtent3D() documentation.
     596             : 
     597             :  Virtual method implemented by drivers since 3.11. In previous versions,
     598             :  GetExtent3D() itself was the virtual method.
     599             : 
     600             :  Driver implementations, when wanting to call the base method, must take
     601             :  care of calling OGRLayer::IGetExtent3D() (and note the public method without
     602             :  the leading I).
     603             : 
     604             :  @param iGeomField 0-based index of the geometry field to consider.
     605             :  @param psExtent3D the computed 3D extent of the layer.
     606             :  @param bForce if TRUE, the extent will be computed even if all the
     607             :         layer features have to be fetched.
     608             :  @return OGRERR_NONE on success or an error code in case of failure.
     609             :  @since GDAL 3.11
     610             : */
     611             : 
     612          27 : OGRErr OGRLayer::IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
     613             :                               bool bForce)
     614             : 
     615             : {
     616             :     /* -------------------------------------------------------------------- */
     617             :     /*      If not forced, we should avoid having to scan all the           */
     618             :     /*      features and just return a failure.                             */
     619             :     /* -------------------------------------------------------------------- */
     620          27 :     if (!bForce)
     621           0 :         return OGRERR_FAILURE;
     622             : 
     623             :     /* -------------------------------------------------------------------- */
     624             :     /*      OK, we hate to do this, but go ahead and read through all       */
     625             :     /*      the features to collect geometries and build extents.           */
     626             :     /* -------------------------------------------------------------------- */
     627          27 :     OGREnvelope3D oEnv;
     628          27 :     bool bExtentSet = false;
     629             : 
     630         133 :     for (auto &&poFeature : *this)
     631             :     {
     632         106 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     633         106 :         if (poGeom == nullptr || poGeom->IsEmpty())
     634             :         {
     635             :             /* Do nothing */
     636             :         }
     637          89 :         else if (!bExtentSet)
     638             :         {
     639          27 :             poGeom->getEnvelope(psExtent3D);
     640             :             // This is required because getEnvelope initializes Z to 0 for 2D geometries
     641          27 :             if (!poGeom->Is3D())
     642             :             {
     643          20 :                 psExtent3D->MinZ = std::numeric_limits<double>::infinity();
     644          20 :                 psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
     645             :             }
     646          27 :             bExtentSet = true;
     647             :         }
     648             :         else
     649             :         {
     650          62 :             poGeom->getEnvelope(&oEnv);
     651             :             // This is required because getEnvelope initializes Z to 0 for 2D geometries
     652          62 :             if (!poGeom->Is3D())
     653             :             {
     654          53 :                 oEnv.MinZ = std::numeric_limits<double>::infinity();
     655          53 :                 oEnv.MaxZ = -std::numeric_limits<double>::infinity();
     656             :             }
     657             :             // Merge handles infinity correctly
     658          62 :             psExtent3D->Merge(oEnv);
     659             :         }
     660             :     }
     661          27 :     ResetReading();
     662             : 
     663          27 :     return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
     664             : }
     665             : 
     666             : /************************************************************************/
     667             : /*                         OGR_L_GetExtent3D()                          */
     668             : /************************************************************************/
     669             : 
     670             : /**
     671             :  \brief Fetch the 3D extent of this layer, on the specified geometry field.
     672             : 
     673             :  Returns the 3D extent (MBR) of the data in the layer.  If bForce is FALSE,
     674             :  and it would be expensive to establish the extent then OGRERR_FAILURE
     675             :  will be returned indicating that the extent isn't know.  If bForce is
     676             :  TRUE then some implementations will actually scan the entire layer once
     677             :  to compute the MBR of all the features in the layer.
     678             : 
     679             :  (Contrary to GetExtent() 2D), the returned extent will always take into
     680             :  account the attribute and spatial filters that may be installed.
     681             : 
     682             :  Layers without any geometry may return OGRERR_FAILURE just indicating that
     683             :  no meaningful extents could be collected.
     684             : 
     685             :  For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
     686             :  fields will be respectively set to +Infinity and -Infinity.
     687             : 
     688             :  Note that some implementations of this method may alter the read cursor
     689             :  of the layer.
     690             : 
     691             :  This function is the same as the C++ method OGRLayer::GetExtent3D().
     692             : 
     693             :  @param hLayer the layer to consider.
     694             :  @param iGeomField 0-based index of the geometry field to consider.
     695             :  @param psExtent3D the computed 3D extent of the layer.
     696             :  @param bForce if TRUE, the extent will be computed even if all the
     697             :         layer features have to be fetched.
     698             :  @return OGRERR_NONE on success or an error code in case of failure.
     699             :  @since GDAL 3.9
     700             : */
     701             : 
     702          62 : OGRErr OGR_L_GetExtent3D(OGRLayerH hLayer, int iGeomField,
     703             :                          OGREnvelope3D *psExtent3D, int bForce)
     704             : 
     705             : {
     706          62 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent3D", OGRERR_INVALID_HANDLE);
     707             : 
     708             : #ifdef OGRAPISPY_ENABLED
     709          62 :     if (bOGRAPISpyEnabled)
     710           0 :         OGRAPISpy_L_GetExtent3D(hLayer, iGeomField, bForce);
     711             : #endif
     712             : 
     713          62 :     return OGRLayer::FromHandle(hLayer)->GetExtent3D(iGeomField, psExtent3D,
     714          62 :                                                      bForce != FALSE);
     715             : }
     716             : 
     717             : /************************************************************************/
     718             : /*                         SetAttributeFilter()                         */
     719             : /************************************************************************/
     720             : 
     721             : /**
     722             :  \brief Set a new attribute query.
     723             : 
     724             :  This method sets the attribute query string to be used when
     725             :  fetching features via the GetNextFeature() method.  Only features for which
     726             :  the query evaluates as true will be returned.
     727             : 
     728             :  The query string should be in the format of an SQL WHERE clause.  For
     729             :  instance "population > 1000000 and population < 5000000" where population
     730             :  is an attribute in the layer. The query format is normally a SQL WHERE clause
     731             :  as described in the
     732             :  <a href="https://gdal.org/user/ogr_sql_dialect.html#where">"WHERE"</a> section
     733             :  of the OGR SQL dialect documentation.
     734             :  In some cases (RDBMS backed drivers, SQLite, GeoPackage) the native
     735             :  capabilities of the database may be used to to interpret the WHERE clause, in
     736             :  which case the capabilities will be broader than those of OGR SQL.
     737             : 
     738             :  Note that installing a query string will generally result in resetting
     739             :  the current reading position (ala ResetReading()).
     740             : 
     741             :  This method is the same as the C function OGR_L_SetAttributeFilter().
     742             : 
     743             :  @param pszQuery query in restricted SQL WHERE format, or NULL to clear the
     744             :  current query.
     745             : 
     746             :  @see GetAttrQueryString() to retrieve the currently installed query string.
     747             : 
     748             :  @return OGRERR_NONE if successfully installed, or an error code if the
     749             :  query expression is in error, or some other failure occurs.
     750             :  */
     751             : 
     752       17111 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
     753             : 
     754             : {
     755       17111 :     CPLFree(m_pszAttrQueryString);
     756       17111 :     m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
     757             : 
     758             :     /* -------------------------------------------------------------------- */
     759             :     /*      Are we just clearing any existing query?                        */
     760             :     /* -------------------------------------------------------------------- */
     761       17111 :     if (pszQuery == nullptr || strlen(pszQuery) == 0)
     762             :     {
     763       11377 :         if (m_poAttrQuery)
     764             :         {
     765        3367 :             delete m_poAttrQuery;
     766        3367 :             m_poAttrQuery = nullptr;
     767        3367 :             ResetReading();
     768             :         }
     769       11377 :         return OGRERR_NONE;
     770             :     }
     771             : 
     772             :     /* -------------------------------------------------------------------- */
     773             :     /*      Or are we installing a new query?                               */
     774             :     /* -------------------------------------------------------------------- */
     775             :     OGRErr eErr;
     776             : 
     777        5734 :     if (!m_poAttrQuery)
     778        4081 :         m_poAttrQuery = new OGRFeatureQuery();
     779             : 
     780        5734 :     eErr = m_poAttrQuery->Compile(this, pszQuery);
     781        5734 :     if (eErr != OGRERR_NONE)
     782             :     {
     783           3 :         delete m_poAttrQuery;
     784           3 :         m_poAttrQuery = nullptr;
     785             :     }
     786             : 
     787        5734 :     ResetReading();
     788             : 
     789        5734 :     return eErr;
     790             : }
     791             : 
     792             : /************************************************************************/
     793             : /*                      ContainGeomSpecialField()                       */
     794             : /************************************************************************/
     795             : 
     796         307 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
     797             : {
     798         307 :     if (expr->eNodeType == SNT_COLUMN)
     799             :     {
     800          68 :         if (expr->table_index == 0 && expr->field_index != -1)
     801             :         {
     802          68 :             int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
     803          68 :             return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
     804         136 :                    nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
     805          68 :                    nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
     806             :         }
     807             :     }
     808         239 :     else if (expr->eNodeType == SNT_OPERATION)
     809             :     {
     810         360 :         for (int i = 0; i < expr->nSubExprCount; i++)
     811             :         {
     812         236 :             if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
     813           0 :                 return TRUE;
     814             :         }
     815             :     }
     816         239 :     return FALSE;
     817             : }
     818             : 
     819             : /************************************************************************/
     820             : /*               AttributeFilterEvaluationNeedsGeometry()               */
     821             : /************************************************************************/
     822             : 
     823             : //! @cond Doxygen_Suppress
     824          71 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
     825             : {
     826          71 :     if (!m_poAttrQuery)
     827           0 :         return FALSE;
     828             : 
     829             :     swq_expr_node *expr =
     830          71 :         static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
     831          71 :     int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
     832             : 
     833          71 :     return ContainGeomSpecialField(expr, nLayerFieldCount);
     834             : }
     835             : 
     836             : //! @endcond
     837             : 
     838             : /************************************************************************/
     839             : /*                      OGR_L_SetAttributeFilter()                      */
     840             : /************************************************************************/
     841             : 
     842             : /**
     843             :  \brief Set a new attribute query.
     844             : 
     845             :  This function sets the attribute query string to be used when
     846             :  fetching features via the OGR_L_GetNextFeature() function.
     847             :  Only features for which the query evaluates as true will be returned.
     848             : 
     849             :  The query string should be in the format of an SQL WHERE clause.  For
     850             :  instance "population > 1000000 and population < 5000000" where population
     851             :  is an attribute in the layer. The query format is normally a SQL WHERE clause
     852             :  as described in the
     853             :  <a href="https://gdal.org/user/ogr_sql_dialect.html#where">"WHERE"</a> section
     854             :  of the OGR SQL dialect documentation.
     855             :  In some cases (RDBMS backed drivers, SQLite, GeoPackage) the native
     856             :  capabilities of the database may be used to to interpret the WHERE clause, in
     857             :  which case the capabilities will be broader than those of OGR SQL.
     858             : 
     859             :  Note that installing a query string will generally result in resetting
     860             :  the current reading position (ala OGR_L_ResetReading()).
     861             : 
     862             :  This function is the same as the C++ method OGRLayer::SetAttributeFilter().
     863             : 
     864             :  @param hLayer handle to the layer on which attribute query will be executed.
     865             :  @param pszQuery query in restricted SQL WHERE format, or NULL to clear the
     866             :  current query.
     867             : 
     868             :  @return OGRERR_NONE if successfully installed, or an error code if the
     869             :  query expression is in error, or some other failure occurs.
     870             :  */
     871             : 
     872        1465 : OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
     873             : 
     874             : {
     875        1465 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
     876             :                       OGRERR_INVALID_HANDLE);
     877             : 
     878             : #ifdef OGRAPISPY_ENABLED
     879        1465 :     if (bOGRAPISpyEnabled)
     880           4 :         OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
     881             : #endif
     882             : 
     883        1465 :     return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
     884             : }
     885             : 
     886             : /************************************************************************/
     887             : /*                      OGR_L_GetAttributeFilter()                      */
     888             : /************************************************************************/
     889             : 
     890             : /**
     891             :  * @brief Fetch the current attribute query string.
     892             :  *
     893             :  * This function is the same as the C++ method OGRLayer::GetAttrQueryString().
     894             :  *
     895             :  * @return the current attribute query string, or NULL if no attribute query is
     896             :  * currently installed. The returned string is short lived and owned by the layer
     897             :  * and should not be modified or freed by the caller.
     898             :  *
     899             :  * @see OGR_L_SetAttributeFilter() to set a new attribute query string.
     900             :  * @since GDAL 3.13
     901             :  */
     902           3 : const char *OGR_L_GetAttributeFilter(OGRLayerH hLayer)
     903             : {
     904           3 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetAttributeFilter", nullptr);
     905             : 
     906           3 :     return OGRLayer::FromHandle(hLayer)->GetAttrQueryString();
     907             : }
     908             : 
     909             : /************************************************************************/
     910             : /*                             GetFeature()                             */
     911             : /************************************************************************/
     912             : 
     913             : /**
     914             :  \brief Fetch a feature by its identifier.
     915             : 
     916             :  This function will attempt to read the identified feature.  The nFID
     917             :  value cannot be OGRNullFID.  Success or failure of this operation is
     918             :  unaffected by the spatial or attribute filters (and specialized implementations
     919             :  in drivers should make sure that they do not take into account spatial or
     920             :  attribute filters).
     921             : 
     922             :  If this method returns a non-NULL feature, it is guaranteed that its
     923             :  feature id (OGRFeature::GetFID()) will be the same as nFID.
     924             : 
     925             :  Use OGRLayer::TestCapability(OLCRandomRead) to establish if this layer
     926             :  supports efficient random access reading via GetFeature(); however, the
     927             :  call should always work if the feature exists as a fallback implementation
     928             :  just scans all the features in the layer looking for the desired feature.
     929             : 
     930             :  Sequential reads (with GetNextFeature()) are generally considered interrupted
     931             :  by a GetFeature() call.
     932             : 
     933             :  The returned feature should be free with OGRFeature::DestroyFeature().
     934             : 
     935             :  This method is the same as the C function OGR_L_GetFeature().
     936             : 
     937             :  @param nFID the feature id of the feature to read.
     938             : 
     939             :  @return a feature now owned by the caller, or NULL on failure.
     940             : */
     941             : 
     942        1085 : OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
     943             : 
     944             : {
     945             :     /* Save old attribute and spatial filters */
     946             :     char *pszOldFilter =
     947        1085 :         m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
     948             :     OGRGeometry *poOldFilterGeom =
     949        1085 :         (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
     950        1085 :     int iOldGeomFieldFilter = m_iGeomFieldFilter;
     951             :     /* Unset filters */
     952        1085 :     SetAttributeFilter(nullptr);
     953        1085 :     SetSpatialFilter(0, nullptr);
     954             : 
     955        1085 :     OGRFeatureUniquePtr poFeature;
     956       14856 :     for (auto &&poFeatureIter : *this)
     957             :     {
     958       13771 :         if (poFeatureIter->GetFID() == nFID)
     959             :         {
     960         713 :             poFeature.swap(poFeatureIter);
     961         713 :             break;
     962             :         }
     963             :     }
     964             : 
     965             :     /* Restore filters */
     966        1085 :     SetAttributeFilter(pszOldFilter);
     967        1085 :     CPLFree(pszOldFilter);
     968        1085 :     SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
     969        1085 :     delete poOldFilterGeom;
     970             : 
     971        2170 :     return poFeature.release();
     972             : }
     973             : 
     974             : /************************************************************************/
     975             : /*                          OGR_L_GetFeature()                          */
     976             : /************************************************************************/
     977             : 
     978             : /**
     979             :  \brief Fetch a feature by its identifier.
     980             : 
     981             :  This function will attempt to read the identified feature.  The nFID
     982             :  value cannot be OGRNullFID.  Success or failure of this operation is
     983             :  unaffected by the spatial or attribute filters (and specialized implementations
     984             :  in drivers should make sure that they do not take into account spatial or
     985             :  attribute filters).
     986             : 
     987             :  If this function returns a non-NULL feature, it is guaranteed that its
     988             :  feature id (OGR_F_GetFID()) will be the same as nFID.
     989             : 
     990             :  Use OGR_L_TestCapability(OLCRandomRead) to establish if this layer
     991             :  supports efficient random access reading via OGR_L_GetFeature(); however,
     992             :  the call should always work if the feature exists as a fallback
     993             :  implementation just scans all the features in the layer looking for the
     994             :  desired feature.
     995             : 
     996             :  Sequential reads (with OGR_L_GetNextFeature()) are generally considered interrupted by a
     997             :  OGR_L_GetFeature() call.
     998             : 
     999             :  The returned feature should be free with OGR_F_Destroy().
    1000             : 
    1001             :  This function is the same as the C++ method OGRLayer::GetFeature( ).
    1002             : 
    1003             :  @param hLayer handle to the layer that owned the feature.
    1004             :  @param nFeatureId the feature id of the feature to read.
    1005             : 
    1006             :  @return a handle to a feature now owned by the caller, or NULL on failure.
    1007             : */
    1008             : 
    1009        2618 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
    1010             : 
    1011             : {
    1012        2618 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
    1013             : 
    1014             : #ifdef OGRAPISPY_ENABLED
    1015        2618 :     if (bOGRAPISpyEnabled)
    1016           2 :         OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
    1017             : #endif
    1018             : 
    1019        2618 :     return OGRFeature::ToHandle(
    1020        5236 :         OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
    1021             : }
    1022             : 
    1023             : /************************************************************************/
    1024             : /*                           SetNextByIndex()                           */
    1025             : /************************************************************************/
    1026             : 
    1027             : /**
    1028             :  \brief Move read cursor to the nIndex'th feature in the current resultset.
    1029             : 
    1030             :  This method allows positioning of a layer such that the GetNextFeature()
    1031             :  call will read the requested feature, where nIndex is an absolute index
    1032             :  into the current result set.   So, setting it to 3 would mean the next
    1033             :  feature read with GetNextFeature() would have been the 4th feature to have
    1034             :  been read if sequential reading took place from the beginning of the layer,
    1035             :  including accounting for spatial and attribute filters.
    1036             : 
    1037             :  Only in rare circumstances is SetNextByIndex() efficiently implemented.
    1038             :  In all other cases the default implementation which calls ResetReading()
    1039             :  and then calls GetNextFeature() nIndex times is used.  To determine if
    1040             :  fast seeking is available on the current layer use the TestCapability()
    1041             :  method with a value of OLCFastSetNextByIndex.
    1042             : 
    1043             :  Starting with GDAL 3.12, when implementations can detect that nIndex is
    1044             :  invalid (at the minimum all should detect negative indices), they should
    1045             :  return OGRERR_NON_EXISTING_FEATURE, and following calls to GetNextFeature()
    1046             :  should return nullptr, until ResetReading() or a valid call to
    1047             :  SetNextByIndex() is done.
    1048             : 
    1049             :  This method is the same as the C function OGR_L_SetNextByIndex().
    1050             : 
    1051             :  @param nIndex the index indicating how many steps into the result set
    1052             :  to seek.
    1053             : 
    1054             :  @return OGRERR_NONE on success or an error code.
    1055             : */
    1056             : 
    1057        1204 : OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
    1058             : 
    1059             : {
    1060        1204 :     if (nIndex < 0)
    1061         249 :         nIndex = GINTBIG_MAX;
    1062             : 
    1063        1204 :     ResetReading();
    1064             : 
    1065      133273 :     while (nIndex-- > 0)
    1066             :     {
    1067      132567 :         auto poFeature = std::unique_ptr<OGRFeature>(GetNextFeature());
    1068      132567 :         if (poFeature == nullptr)
    1069         498 :             return OGRERR_NON_EXISTING_FEATURE;
    1070             :     }
    1071             : 
    1072         706 :     return OGRERR_NONE;
    1073             : }
    1074             : 
    1075             : /************************************************************************/
    1076             : /*                        OGR_L_SetNextByIndex()                        */
    1077             : /************************************************************************/
    1078             : 
    1079             : /**
    1080             :  \brief Move read cursor to the nIndex'th feature in the current resultset.
    1081             : 
    1082             :  This method allows positioning of a layer such that the GetNextFeature()
    1083             :  call will read the requested feature, where nIndex is an absolute index
    1084             :  into the current result set.   So, setting it to 3 would mean the next
    1085             :  feature read with GetNextFeature() would have been the 4th feature to have
    1086             :  been read if sequential reading took place from the beginning of the layer,
    1087             :  including accounting for spatial and attribute filters.
    1088             : 
    1089             :  Only in rare circumstances is SetNextByIndex() efficiently implemented.
    1090             :  In all other cases the default implementation which calls ResetReading()
    1091             :  and then calls GetNextFeature() nIndex times is used.  To determine if
    1092             :  fast seeking is available on the current layer use the TestCapability()
    1093             :  method with a value of OLCFastSetNextByIndex.
    1094             : 
    1095             :  Starting with GDAL 3.12, when implementations can detect that nIndex is
    1096             :  invalid (at the minimum all should detect negative indices), they should
    1097             :  return OGRERR_NON_EXISTING_FEATURE, and following calls to GetNextFeature()
    1098             :  should return nullptr, until ResetReading() or a valid call to
    1099             :  SetNextByIndex() is done.
    1100             : 
    1101             :  This method is the same as the C++ method OGRLayer::SetNextByIndex()
    1102             : 
    1103             :  @param hLayer handle to the layer
    1104             :  @param nIndex the index indicating how many steps into the result set
    1105             :  to seek.
    1106             : 
    1107             :  @return OGRERR_NONE on success or an error code.
    1108             : */
    1109             : 
    1110          41 : OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
    1111             : 
    1112             : {
    1113          41 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
    1114             : 
    1115             : #ifdef OGRAPISPY_ENABLED
    1116          41 :     if (bOGRAPISpyEnabled)
    1117           2 :         OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
    1118             : #endif
    1119             : 
    1120          41 :     return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
    1121             : }
    1122             : 
    1123             : /************************************************************************/
    1124             : /*                      OGRLayer::GetNextFeature()                      */
    1125             : /************************************************************************/
    1126             : 
    1127             : /**
    1128             :  \fn OGRFeature *OGRLayer::GetNextFeature();
    1129             : 
    1130             :  \brief Fetch the next available feature from this layer.
    1131             : 
    1132             :  The returned feature becomes the responsibility of the caller to
    1133             :  delete with OGRFeature::DestroyFeature(). It is critical that all
    1134             :  features associated with an OGRLayer (more specifically an
    1135             :  OGRFeatureDefn) be deleted before that layer/datasource is deleted.
    1136             : 
    1137             :  Only features matching the current spatial filter (set with
    1138             :  SetSpatialFilter()) will be returned.
    1139             : 
    1140             :  This method implements sequential access to the features of a layer.  The
    1141             :  ResetReading() method can be used to start at the beginning again.
    1142             : 
    1143             :  Starting with GDAL 3.6, it is possible to retrieve them by batches, with a
    1144             :  column-oriented memory layout, using the GetArrowStream() method.
    1145             : 
    1146             :  Features returned by GetNextFeature() may or may not be affected by
    1147             :  concurrent modifications depending on drivers. A guaranteed way of seeing
    1148             :  modifications in effect is to call ResetReading() on layers where
    1149             :  GetNextFeature() has been called, before reading again.  Structural changes
    1150             :  in layers (field addition, deletion, ...) when a read is in progress may or
    1151             :  may not be possible depending on drivers.  If a transaction is
    1152             :  committed/aborted, the current sequential reading may or may not be valid
    1153             :  after that operation and a call to ResetReading() might be needed.
    1154             : 
    1155             :  This method is the same as the C function OGR_L_GetNextFeature().
    1156             : 
    1157             :  @return a feature, or NULL if no more features are available.
    1158             : 
    1159             : */
    1160             : 
    1161             : /************************************************************************/
    1162             : /*                        OGR_L_GetNextFeature()                        */
    1163             : /************************************************************************/
    1164             : 
    1165             : /**
    1166             :  \brief Fetch the next available feature from this layer.
    1167             : 
    1168             :  The returned feature becomes the responsibility of the caller to
    1169             :  delete with OGR_F_Destroy().  It is critical that all features
    1170             :  associated with an OGRLayer (more specifically an OGRFeatureDefn) be
    1171             :  deleted before that layer/datasource is deleted.
    1172             : 
    1173             :  Only features matching the current spatial filter (set with
    1174             :  SetSpatialFilter()) will be returned.
    1175             : 
    1176             :  This function implements sequential access to the features of a layer.
    1177             :  The OGR_L_ResetReading() function can be used to start at the beginning
    1178             :  again.
    1179             : 
    1180             :  Starting with GDAL 3.6, it is possible to retrieve them by batches, with a
    1181             :  column-oriented memory layout, using the OGR_L_GetArrowStream() function.
    1182             : 
    1183             :  Features returned by OGR_GetNextFeature() may or may not be affected by
    1184             :  concurrent modifications depending on drivers. A guaranteed way of seeing
    1185             :  modifications in effect is to call OGR_L_ResetReading() on layers where
    1186             :  OGR_GetNextFeature() has been called, before reading again.  Structural
    1187             :  changes in layers (field addition, deletion, ...) when a read is in progress
    1188             :  may or may not be possible depending on drivers.  If a transaction is
    1189             :  committed/aborted, the current sequential reading may or may not be valid
    1190             :  after that operation and a call to OGR_L_ResetReading() might be needed.
    1191             : 
    1192             :  This function is the same as the C++ method OGRLayer::GetNextFeature().
    1193             : 
    1194             :  @param hLayer handle to the layer from which feature are read.
    1195             :  @return a handle to a feature, or NULL if no more features are available.
    1196             : 
    1197             : */
    1198             : 
    1199       94997 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
    1200             : 
    1201             : {
    1202       94997 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
    1203             : 
    1204             : #ifdef OGRAPISPY_ENABLED
    1205       94997 :     if (bOGRAPISpyEnabled)
    1206           8 :         OGRAPISpy_L_GetNextFeature(hLayer);
    1207             : #endif
    1208             : 
    1209       94997 :     return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
    1210             : }
    1211             : 
    1212             : /************************************************************************/
    1213             : /*                      ConvertGeomsIfNecessary()                       */
    1214             : /************************************************************************/
    1215             : 
    1216      991880 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
    1217             : {
    1218      991880 :     if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
    1219             :     {
    1220             :         // One time initialization
    1221       10639 :         m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
    1222       10639 :         m_poPrivate->m_bSupportsCurve =
    1223       10639 :             CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
    1224       10639 :         m_poPrivate->m_bSupportsM =
    1225       10639 :             CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
    1226       10639 :         if (CPLTestBool(
    1227             :                 CPLGetConfigOption("OGR_APPLY_GEOM_SET_PRECISION", "FALSE")))
    1228             :         {
    1229           2 :             const auto poFeatureDefn = GetLayerDefn();
    1230           2 :             const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
    1231           2 :             for (int i = 0; i < nGeomFieldCount; i++)
    1232             :             {
    1233           2 :                 const double dfXYResolution = poFeatureDefn->GetGeomFieldDefn(i)
    1234           2 :                                                   ->GetCoordinatePrecision()
    1235           2 :                                                   .dfXYResolution;
    1236           4 :                 if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
    1237           2 :                     OGRGeometryFactory::haveGEOS())
    1238             :                 {
    1239           2 :                     m_poPrivate->m_bApplyGeomSetPrecision = true;
    1240           2 :                     break;
    1241             :                 }
    1242             :             }
    1243             :         }
    1244             :     }
    1245             : 
    1246     1891590 :     if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
    1247      899707 :         m_poPrivate->m_bApplyGeomSetPrecision)
    1248             :     {
    1249       92175 :         const auto poFeatureDefn = GetLayerDefn();
    1250       92175 :         const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
    1251      182043 :         for (int i = 0; i < nGeomFieldCount; i++)
    1252             :         {
    1253       89868 :             OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
    1254       89868 :             if (poGeom)
    1255             :             {
    1256      106279 :                 if (!m_poPrivate->m_bSupportsM &&
    1257       19388 :                     OGR_GT_HasM(poGeom->getGeometryType()))
    1258             :                 {
    1259           5 :                     poGeom->setMeasured(FALSE);
    1260             :                 }
    1261             : 
    1262      173584 :                 if (!m_poPrivate->m_bSupportsCurve &&
    1263       86693 :                     OGR_GT_IsNonLinear(poGeom->getGeometryType()))
    1264             :                 {
    1265             :                     OGRwkbGeometryType eTargetType =
    1266          31 :                         OGR_GT_GetLinear(poGeom->getGeometryType());
    1267             :                     auto poGeomUniquePtr = OGRGeometryFactory::forceTo(
    1268          31 :                         std::unique_ptr<OGRGeometry>(
    1269             :                             poFeature->StealGeometry(i)),
    1270          31 :                         eTargetType);
    1271          31 :                     poFeature->SetGeomField(i, std::move(poGeomUniquePtr));
    1272          31 :                     poGeom = poFeature->GetGeomFieldRef(i);
    1273             :                 }
    1274             : 
    1275       86891 :                 if (poGeom && m_poPrivate->m_bApplyGeomSetPrecision)
    1276             :                 {
    1277             :                     const double dfXYResolution =
    1278           2 :                         poFeatureDefn->GetGeomFieldDefn(i)
    1279           2 :                             ->GetCoordinatePrecision()
    1280           2 :                             .dfXYResolution;
    1281           4 :                     if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
    1282           2 :                         !poGeom->hasCurveGeometry())
    1283             :                     {
    1284           2 :                         auto poNewGeom = poGeom->SetPrecision(dfXYResolution,
    1285             :                                                               /* nFlags = */ 0);
    1286           2 :                         if (poNewGeom)
    1287             :                         {
    1288           2 :                             poFeature->SetGeomFieldDirectly(i, poNewGeom);
    1289             :                             // If there was potential further processing...
    1290             :                             // poGeom = poFeature->GetGeomFieldRef(i);
    1291             :                         }
    1292             :                     }
    1293             :                 }
    1294             :             }
    1295             :         }
    1296             :     }
    1297      991880 : }
    1298             : 
    1299             : /************************************************************************/
    1300             : /*                             SetFeature()                             */
    1301             : /************************************************************************/
    1302             : 
    1303             : /**
    1304             :  \brief Rewrite/replace an existing feature.
    1305             : 
    1306             :  This method will write a feature to the layer, based on the feature id
    1307             :  within the OGRFeature.
    1308             : 
    1309             :  Use OGRLayer::TestCapability(OLCRandomWrite) to establish if this layer
    1310             :  supports random access writing via SetFeature().
    1311             : 
    1312             :  The way unset fields in the provided poFeature are processed is driver dependent:
    1313             :  <ul>
    1314             :  <li>
    1315             :  SQL based drivers which implement SetFeature() through SQL UPDATE will skip
    1316             :  unset fields, and thus the content of the existing feature will be preserved.
    1317             :  </li>
    1318             :  <li>
    1319             :  The shapefile driver will write a NULL value in the DBF file.
    1320             :  </li>
    1321             :  <li>
    1322             :  The GeoJSON driver will take into account unset fields to remove the corresponding
    1323             :  JSON member.
    1324             :  </li>
    1325             :  </ul>
    1326             : 
    1327             :  Drivers should specialize the ISetFeature() method.
    1328             : 
    1329             :  This method is the same as the C function OGR_L_SetFeature().
    1330             : 
    1331             :  To set a feature, but create it if it doesn't exist see OGRLayer::UpsertFeature().
    1332             : 
    1333             :  @param poFeature the feature to write.
    1334             : 
    1335             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    1336             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    1337             : 
    1338             :  @see UpdateFeature(), CreateFeature(), UpsertFeature()
    1339             : */
    1340             : 
    1341        3179 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
    1342             : 
    1343             : {
    1344        3179 :     ConvertGeomsIfNecessary(poFeature);
    1345        3179 :     return ISetFeature(poFeature);
    1346             : }
    1347             : 
    1348             : /************************************************************************/
    1349             : /*                            ISetFeature()                             */
    1350             : /************************************************************************/
    1351             : 
    1352             : /**
    1353             :  \brief Rewrite/replace an existing feature.
    1354             : 
    1355             :  This method is implemented by drivers and not called directly. User code should
    1356             :  use SetFeature() instead.
    1357             : 
    1358             :  This method will write a feature to the layer, based on the feature id
    1359             :  within the OGRFeature.
    1360             : 
    1361             :  @param poFeature the feature to write.
    1362             : 
    1363             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    1364             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    1365             : 
    1366             :  @see SetFeature()
    1367             : */
    1368             : 
    1369         199 : OGRErr OGRLayer::ISetFeature(OGRFeature *poFeature)
    1370             : 
    1371             : {
    1372             :     (void)poFeature;
    1373         199 :     return OGRERR_UNSUPPORTED_OPERATION;
    1374             : }
    1375             : 
    1376             : /************************************************************************/
    1377             : /*                          OGR_L_SetFeature()                          */
    1378             : /************************************************************************/
    1379             : 
    1380             : /**
    1381             :  \brief Rewrite/replace an existing feature.
    1382             : 
    1383             :  This function will write a feature to the layer, based on the feature id
    1384             :  within the OGRFeature.
    1385             : 
    1386             :  Use OGR_L_TestCapability(OLCRandomWrite) to establish if this layer
    1387             :  supports random access writing via OGR_L_SetFeature().
    1388             : 
    1389             :  The way unset fields in the provided poFeature are processed is driver dependent:
    1390             :  <ul>
    1391             :  <li>
    1392             :  SQL based drivers which implement SetFeature() through SQL UPDATE will skip
    1393             :  unset fields, and thus the content of the existing feature will be preserved.
    1394             :  </li>
    1395             :  <li>
    1396             :  The shapefile driver will write a NULL value in the DBF file.
    1397             :  </li>
    1398             :  <li>
    1399             :  The GeoJSON driver will take into account unset fields to remove the corresponding
    1400             :  JSON member.
    1401             :  </li>
    1402             :  </ul>
    1403             : 
    1404             :  This function is the same as the C++ method OGRLayer::SetFeature().
    1405             : 
    1406             :  To set a feature, but create it if it doesn't exist see OGR_L_UpsertFeature().
    1407             : 
    1408             :  @param hLayer handle to the layer to write the feature.
    1409             :  @param hFeat the feature to write.
    1410             : 
    1411             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    1412             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    1413             : 
    1414             :  @see OGR_L_UpdateFeature(), OGR_L_CreateFeature(), OGR_L_UpsertFeature()
    1415             : */
    1416             : 
    1417        2479 : OGRErr OGR_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
    1418             : 
    1419             : {
    1420        2479 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
    1421        2479 :     VALIDATE_POINTER1(hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
    1422             : 
    1423             : #ifdef OGRAPISPY_ENABLED
    1424        2479 :     if (bOGRAPISpyEnabled)
    1425           2 :         OGRAPISpy_L_SetFeature(hLayer, hFeat);
    1426             : #endif
    1427             : 
    1428        2479 :     return OGRLayer::FromHandle(hLayer)->SetFeature(
    1429        2479 :         OGRFeature::FromHandle(hFeat));
    1430             : }
    1431             : 
    1432             : /************************************************************************/
    1433             : /*                             SetFeature()                             */
    1434             : /************************************************************************/
    1435             : 
    1436             : /**
    1437             :  \brief Rewrite/replace an existing feature, transferring ownership
    1438             :         of the feature to the layer
    1439             : 
    1440             :  This method will write a feature to the layer, based on the feature id
    1441             :  within the OGRFeature.
    1442             : 
    1443             :  Use OGRLayer::TestCapability(OLCRandomWrite) to establish if this layer
    1444             :  supports random access writing via SetFeature().
    1445             : 
    1446             :  The way unset fields in the provided poFeature are processed is driver dependent:
    1447             :  <ul>
    1448             :  <li>
    1449             :  SQL based drivers which implement SetFeature() through SQL UPDATE will skip
    1450             :  unset fields, and thus the content of the existing feature will be preserved.
    1451             :  </li>
    1452             :  <li>
    1453             :  The shapefile driver will write a NULL value in the DBF file.
    1454             :  </li>
    1455             :  <li>
    1456             :  The GeoJSON driver will take into account unset fields to remove the corresponding
    1457             :  JSON member.
    1458             :  </li>
    1459             :  </ul>
    1460             : 
    1461             :  Drivers should specialize the ISetFeatureUniqPtr() method.
    1462             : 
    1463             :  To set a feature, but create it if it doesn't exist see OGRLayer::UpsertFeature().
    1464             : 
    1465             :  @param poFeature the feature to write.
    1466             : 
    1467             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    1468             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    1469             : 
    1470             :  @see UpdateFeature(), CreateFeature(), UpsertFeature()
    1471             :  @since 3.13
    1472             : */
    1473             : 
    1474         534 : OGRErr OGRLayer::SetFeature(std::unique_ptr<OGRFeature> poFeature)
    1475             : 
    1476             : {
    1477         534 :     ConvertGeomsIfNecessary(poFeature.get());
    1478         534 :     return ISetFeatureUniqPtr(std::move(poFeature));
    1479             : }
    1480             : 
    1481             : /************************************************************************/
    1482             : /*                         ISetFeatureUniqPtr()                         */
    1483             : /************************************************************************/
    1484             : 
    1485             : /**
    1486             :  \brief Rewrite/replace an existing feature, transferring ownership
    1487             :         of the feature to the layer
    1488             : 
    1489             :  WARNING: if drivers implement this method, they *MUST* also implement
    1490             :  ISetFeature()
    1491             : 
    1492             :  This method is implemented by drivers and not called directly. User code should
    1493             :  use SetFeature() instead.
    1494             : 
    1495             :  This method will write a feature to the layer, based on the feature id
    1496             :  within the OGRFeature.
    1497             : 
    1498             :  @param poFeature the feature to write.
    1499             : 
    1500             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    1501             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    1502             : 
    1503             :  @see SetFeature()
    1504             :  @since 3.13
    1505             : */
    1506             : 
    1507           0 : OGRErr OGRLayer::ISetFeatureUniqPtr(std::unique_ptr<OGRFeature> poFeature)
    1508             : 
    1509             : {
    1510           0 :     return ISetFeature(poFeature.get());
    1511             : }
    1512             : 
    1513             : /************************************************************************/
    1514             : /*                           CreateFeature()                            */
    1515             : /************************************************************************/
    1516             : 
    1517             : /**
    1518             :  \brief Create and write a new feature within a layer.
    1519             : 
    1520             :  The passed feature is written to the layer as a new feature, rather than
    1521             :  overwriting an existing one.  If the feature has a feature id other than
    1522             :  OGRNullFID, then the native implementation may use that as the feature id
    1523             :  of the new feature, but not necessarily.  Upon successful return the
    1524             :  passed feature will have been updated with the new feature id.
    1525             : 
    1526             :  Drivers should specialize the ICreateFeature() method.
    1527             : 
    1528             :  This method is the same as the C function OGR_L_CreateFeature().
    1529             : 
    1530             :  To create a feature, but set it if it exists see OGRLayer::UpsertFeature().
    1531             : 
    1532             :  @param poFeature the feature to write to disk.
    1533             : 
    1534             :  @return OGRERR_NONE on success.
    1535             : 
    1536             :  @see SetFeature(), UpdateFeature(), UpsertFeature()
    1537             : */
    1538             : 
    1539      667361 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
    1540             : 
    1541             : {
    1542      667361 :     ConvertGeomsIfNecessary(poFeature);
    1543      667361 :     return ICreateFeature(poFeature);
    1544             : }
    1545             : 
    1546             : /************************************************************************/
    1547             : /*                           ICreateFeature()                           */
    1548             : /************************************************************************/
    1549             : 
    1550             : /**
    1551             :  \brief Create and write a new feature within a layer.
    1552             : 
    1553             :  This method is implemented by drivers and not called directly. User code should
    1554             :  use CreateFeature() instead.
    1555             : 
    1556             :  The passed feature is written to the layer as a new feature, rather than
    1557             :  overwriting an existing one.  If the feature has a feature id other than
    1558             :  OGRNullFID, then the native implementation may use that as the feature id
    1559             :  of the new feature, but not necessarily.  Upon successful return the
    1560             :  passed feature will have been updated with the new feature id.
    1561             : 
    1562             :  @param poFeature the feature to write to disk.
    1563             : 
    1564             :  @return OGRERR_NONE on success.
    1565             : 
    1566             :  @see CreateFeature()
    1567             : */
    1568             : 
    1569           0 : OGRErr OGRLayer::ICreateFeature(OGRFeature *poFeature)
    1570             : 
    1571             : {
    1572             :     (void)poFeature;
    1573           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1574             : }
    1575             : 
    1576             : /************************************************************************/
    1577             : /*                        OGR_L_CreateFeature()                         */
    1578             : /************************************************************************/
    1579             : 
    1580             : /**
    1581             :  \brief Create and write a new feature within a layer.
    1582             : 
    1583             :  The passed feature is written to the layer as a new feature, rather than
    1584             :  overwriting an existing one.  If the feature has a feature id other than
    1585             :  OGRNullFID, then the native implementation may use that as the feature id
    1586             :  of the new feature, but not necessarily.  Upon successful return the
    1587             :  passed feature will have been updated with the new feature id.
    1588             : 
    1589             :  This function is the same as the C++ method OGRLayer::CreateFeature().
    1590             : 
    1591             :  To create a feature, but set it if it exists see OGR_L_UpsertFeature().
    1592             : 
    1593             :  @param hLayer handle to the layer to write the feature to.
    1594             :  @param hFeat the handle of the feature to write to disk.
    1595             : 
    1596             :  @return OGRERR_NONE on success.
    1597             : 
    1598             :  @see OGR_L_SetFeature(), OGR_L_UpdateFeature(), OGR_L_UpsertFeature()
    1599             : */
    1600             : 
    1601      299764 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
    1602             : 
    1603             : {
    1604      299764 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
    1605      299764 :     VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
    1606             : 
    1607             : #ifdef OGRAPISPY_ENABLED
    1608      299764 :     if (bOGRAPISpyEnabled)
    1609           5 :         OGRAPISpy_L_CreateFeature(hLayer, hFeat);
    1610             : #endif
    1611             : 
    1612      299764 :     return OGRLayer::FromHandle(hLayer)->CreateFeature(
    1613      299764 :         OGRFeature::FromHandle(hFeat));
    1614             : }
    1615             : 
    1616             : /************************************************************************/
    1617             : /*                           CreateFeature()                            */
    1618             : /************************************************************************/
    1619             : 
    1620             : /**
    1621             :  \brief Create and write a new feature within a layer, transferring ownership
    1622             :         of the feature to the layer
    1623             : 
    1624             :  The passed feature is written to the layer as a new feature, rather than
    1625             :  overwriting an existing one.  If the feature has a feature id other than
    1626             :  OGRNullFID, then the native implementation may use that as the feature id
    1627             :  of the new feature, but not necessarily.  Upon successful return the
    1628             :  passed feature will have been updated with the new feature id.
    1629             : 
    1630             :  Drivers should specialize the ICreateFeatureUniqPtr() method.
    1631             : 
    1632             :  To create a feature, but set it if it exists see OGRLayer::UpsertFeature().
    1633             : 
    1634             :  @param poFeature the feature to write to disk.
    1635             :  @param[out] pnFID Pointer to an integer that will receive the potentially
    1636             :              updated FID
    1637             : 
    1638             :  @return OGRERR_NONE on success.
    1639             : 
    1640             :  @see SetFeature(), UpdateFeature(), UpsertFeature()
    1641             :  @since 3.13
    1642             : */
    1643             : 
    1644      320698 : OGRErr OGRLayer::CreateFeature(std::unique_ptr<OGRFeature> poFeature,
    1645             :                                GIntBig *pnFID)
    1646             : 
    1647             : {
    1648      320698 :     ConvertGeomsIfNecessary(poFeature.get());
    1649      320698 :     return ICreateFeatureUniqPtr(std::move(poFeature), pnFID);
    1650             : }
    1651             : 
    1652             : /************************************************************************/
    1653             : /*                       ICreateFeatureUniqPtr()                        */
    1654             : /************************************************************************/
    1655             : 
    1656             : /**
    1657             :  \brief Create and write a new feature within a layer, transferring ownership
    1658             :         of the feature to the layer
    1659             : 
    1660             :  WARNING: if drivers implement this method, they *MUST* also implement
    1661             :  ICreateFeature()
    1662             : 
    1663             :  The passed feature is written to the layer as a new feature, rather than
    1664             :  overwriting an existing one.  If the feature has a feature id other than
    1665             :  OGRNullFID, then the native implementation may use that as the feature id
    1666             :  of the new feature, but not necessarily.  Upon successful return the
    1667             :  passed feature will have been updated with the new feature id.
    1668             : 
    1669             :  @param poFeature the feature to write to disk.
    1670             :  @param[out] pnFID Pointer to an integer that will receive the potentially
    1671             :              updated FID
    1672             : 
    1673             :  @return OGRERR_NONE on success.
    1674             : 
    1675             :  @see ICreateFeature()
    1676             :  @see CreateFeature(std::unique_ptr<OGRFeature> , GIntBig*)
    1677             :  @since 3.13
    1678             : */
    1679             : 
    1680          15 : OGRErr OGRLayer::ICreateFeatureUniqPtr(std::unique_ptr<OGRFeature> poFeature,
    1681             :                                        GIntBig *pnFID)
    1682             : 
    1683             : {
    1684          15 :     const OGRErr eErr = ICreateFeature(poFeature.get());
    1685          15 :     if (pnFID)
    1686           0 :         *pnFID = poFeature->GetFID();
    1687          15 :     return eErr;
    1688             : }
    1689             : 
    1690             : /************************************************************************/
    1691             : /*                           UpsertFeature()                            */
    1692             : /************************************************************************/
    1693             : 
    1694             : /**
    1695             :  \brief Rewrite/replace an existing feature or create a new feature within a layer.
    1696             : 
    1697             :  This function will write a feature to the layer, based on the feature id
    1698             :  within the OGRFeature.  If the feature id doesn't exist a new feature will be
    1699             :  written.  Otherwise, the existing feature will be rewritten.
    1700             : 
    1701             :  Use OGRLayer::TestCapability(OLCUpsertFeature) to establish if this layer
    1702             :  supports upsert writing.
    1703             : 
    1704             :  This method is the same as the C function OGR_L_UpsertFeature().
    1705             : 
    1706             :  @param poFeature the feature to write to disk.
    1707             : 
    1708             :  @return OGRERR_NONE on success.
    1709             :  @since GDAL 3.6.0
    1710             : 
    1711             :  @see SetFeature(), CreateFeature(), UpdateFeature()
    1712             : */
    1713             : 
    1714          33 : OGRErr OGRLayer::UpsertFeature(OGRFeature *poFeature)
    1715             : 
    1716             : {
    1717          33 :     ConvertGeomsIfNecessary(poFeature);
    1718          33 :     return IUpsertFeature(poFeature);
    1719             : }
    1720             : 
    1721             : /************************************************************************/
    1722             : /*                           IUpsertFeature()                           */
    1723             : /************************************************************************/
    1724             : 
    1725             : /**
    1726             :  \brief Rewrite/replace an existing feature or create a new feature within a layer.
    1727             : 
    1728             :  This method is implemented by drivers and not called directly. User code should
    1729             :  use UpsertFeature() instead.
    1730             : 
    1731             :  This function will write a feature to the layer, based on the feature id
    1732             :  within the OGRFeature.  If the feature id doesn't exist a new feature will be
    1733             :  written.  Otherwise, the existing feature will be rewritten.
    1734             : 
    1735             :  @param poFeature the feature to write to disk.
    1736             : 
    1737             :  @return OGRERR_NONE on success.
    1738             :  @since GDAL 3.6.0
    1739             : 
    1740             :  @see UpsertFeature()
    1741             : */
    1742             : 
    1743           0 : OGRErr OGRLayer::IUpsertFeature(OGRFeature *poFeature)
    1744             : {
    1745             :     (void)poFeature;
    1746           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1747             : }
    1748             : 
    1749             : /************************************************************************/
    1750             : /*                        OGR_L_UpsertFeature()                         */
    1751             : /************************************************************************/
    1752             : 
    1753             : /**
    1754             :  \brief Rewrite/replace an existing feature or create a new feature within a layer.
    1755             : 
    1756             :  This function will write a feature to the layer, based on the feature id
    1757             :  within the OGRFeature.  If the feature id doesn't exist a new feature will be
    1758             :  written.  Otherwise, the existing feature will be rewritten.
    1759             : 
    1760             :  Use OGR_L_TestCapability(OLCUpsertFeature) to establish if this layer
    1761             :  supports upsert writing.
    1762             : 
    1763             :  This function is the same as the C++ method OGRLayer::UpsertFeature().
    1764             : 
    1765             :  @param hLayer handle to the layer to write the feature to.
    1766             :  @param hFeat the handle of the feature to write to disk.
    1767             : 
    1768             :  @return OGRERR_NONE on success.
    1769             :  @since GDAL 3.6.0
    1770             : 
    1771             :  @see OGR_L_SetFeature(), OGR_L_CreateFeature(), OGR_L_UpdateFeature()
    1772             : */
    1773             : 
    1774          31 : OGRErr OGR_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
    1775             : 
    1776             : {
    1777          31 :     VALIDATE_POINTER1(hLayer, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
    1778          31 :     VALIDATE_POINTER1(hFeat, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
    1779             : 
    1780             : #ifdef OGRAPISPY_ENABLED
    1781          31 :     if (bOGRAPISpyEnabled)
    1782           0 :         OGRAPISpy_L_UpsertFeature(hLayer, hFeat);
    1783             : #endif
    1784             : 
    1785          31 :     return OGRLayer::FromHandle(hLayer)->UpsertFeature(
    1786          31 :         OGRFeature::FromHandle(hFeat));
    1787             : }
    1788             : 
    1789             : /************************************************************************/
    1790             : /*                           UpdateFeature()                            */
    1791             : /************************************************************************/
    1792             : 
    1793             : /**
    1794             :  \brief Update (part of) an existing feature.
    1795             : 
    1796             :  This method will update the specified attribute and geometry fields of a
    1797             :  feature to the layer, based on the feature id within the OGRFeature.
    1798             : 
    1799             :  Use OGRLayer::TestCapability(OLCRandomWrite) to establish if this layer
    1800             :  supports random access writing via UpdateFeature(). And to know if the
    1801             :  driver supports a dedicated/efficient UpdateFeature() method, test for the
    1802             :  OLCUpdateFeature capability.
    1803             : 
    1804             :  The way unset fields in the provided poFeature are processed is driver dependent:
    1805             :  <ul>
    1806             :  <li>
    1807             :  SQL based drivers which implement SetFeature() through SQL UPDATE will skip
    1808             :  unset fields, and thus the content of the existing feature will be preserved.
    1809             :  </li>
    1810             :  <li>
    1811             :  The shapefile driver will write a NULL value in the DBF file.
    1812             :  </li>
    1813             :  <li>
    1814             :  The GeoJSON driver will take into account unset fields to remove the corresponding
    1815             :  JSON member.
    1816             :  </li>
    1817             :  </ul>
    1818             : 
    1819             :  This method is the same as the C function OGR_L_UpdateFeature().
    1820             : 
    1821             :  To fully replace a feature, see OGRLayer::SetFeature().
    1822             : 
    1823             :  Note that after this call the content of hFeat might have changed, and will
    1824             :  *not* reflect the content you would get with GetFeature().
    1825             :  In particular for performance reasons, passed geometries might have been "stolen",
    1826             :  in particular for the default implementation of UpdateFeature() which relies
    1827             :  on GetFeature() + SetFeature().
    1828             : 
    1829             :  @param poFeature the feature to update.
    1830             : 
    1831             :  @param nUpdatedFieldsCount number of attribute fields to update. May be 0
    1832             : 
    1833             :  @param panUpdatedFieldsIdx array of nUpdatedFieldsCount values, each between
    1834             :                             0 and GetLayerDefn()->GetFieldCount() - 1, indicating
    1835             :                             which fields of poFeature must be updated in the
    1836             :                             layer.
    1837             : 
    1838             :  @param nUpdatedGeomFieldsCount number of geometry fields to update. May be 0
    1839             : 
    1840             :  @param panUpdatedGeomFieldsIdx array of nUpdatedGeomFieldsCount values, each between
    1841             :                                 0 and GetLayerDefn()->GetGeomFieldCount() - 1, indicating
    1842             :                                 which geometry fields of poFeature must be updated in the
    1843             :                                 layer.
    1844             : 
    1845             :  @param bUpdateStyleString whether the feature style string in the layer should
    1846             :                            be updated with the one of poFeature.
    1847             : 
    1848             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    1849             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    1850             : 
    1851             :  @since GDAL 3.7
    1852             : 
    1853             :  @see UpdateFeature(), CreateFeature(), UpsertFeature()
    1854             : */
    1855             : 
    1856          75 : OGRErr OGRLayer::UpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
    1857             :                                const int *panUpdatedFieldsIdx,
    1858             :                                int nUpdatedGeomFieldsCount,
    1859             :                                const int *panUpdatedGeomFieldsIdx,
    1860             :                                bool bUpdateStyleString)
    1861             : 
    1862             : {
    1863          75 :     ConvertGeomsIfNecessary(poFeature);
    1864          75 :     const int nFieldCount = GetLayerDefn()->GetFieldCount();
    1865         136 :     for (int i = 0; i < nUpdatedFieldsCount; ++i)
    1866             :     {
    1867          63 :         if (panUpdatedFieldsIdx[i] < 0 || panUpdatedFieldsIdx[i] >= nFieldCount)
    1868             :         {
    1869           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    1870             :                      "Invalid panUpdatedFieldsIdx[%d] = %d", i,
    1871           2 :                      panUpdatedFieldsIdx[i]);
    1872           2 :             return OGRERR_FAILURE;
    1873             :         }
    1874             :     }
    1875          73 :     const int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
    1876          83 :     for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
    1877             :     {
    1878          12 :         if (panUpdatedGeomFieldsIdx[i] < 0 ||
    1879          11 :             panUpdatedGeomFieldsIdx[i] >= nGeomFieldCount)
    1880             :         {
    1881           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    1882             :                      "Invalid panUpdatedGeomFieldsIdx[%d] = %d", i,
    1883           2 :                      panUpdatedGeomFieldsIdx[i]);
    1884           2 :             return OGRERR_FAILURE;
    1885             :         }
    1886             :     }
    1887          71 :     return IUpdateFeature(poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
    1888             :                           nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx,
    1889          71 :                           bUpdateStyleString);
    1890             : }
    1891             : 
    1892             : /************************************************************************/
    1893             : /*                           IUpdateFeature()                           */
    1894             : /************************************************************************/
    1895             : 
    1896             : /**
    1897             :  \brief Update (part of) an existing feature.
    1898             : 
    1899             :  This method is implemented by drivers and not called directly. User code should
    1900             :  use UpdateFeature() instead.
    1901             : 
    1902             :  @param poFeature the feature to update.
    1903             : 
    1904             :  @param nUpdatedFieldsCount number of attribute fields to update. May be 0
    1905             : 
    1906             :  @param panUpdatedFieldsIdx array of nUpdatedFieldsCount values, each between
    1907             :                             0 and GetLayerDefn()->GetFieldCount() - 1, indicating
    1908             :                             which fields of poFeature must be updated in the
    1909             :                             layer.
    1910             : 
    1911             :  @param nUpdatedGeomFieldsCount number of geometry fields to update. May be 0
    1912             : 
    1913             :  @param panUpdatedGeomFieldsIdx array of nUpdatedGeomFieldsCount values, each between
    1914             :                                 0 and GetLayerDefn()->GetGeomFieldCount() - 1, indicating
    1915             :                                 which geometry fields of poFeature must be updated in the
    1916             :                                 layer.
    1917             : 
    1918             :  @param bUpdateStyleString whether the feature style string in the layer should
    1919             :                            be updated with the one of poFeature.
    1920             : 
    1921             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    1922             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    1923             : 
    1924             :  @since GDAL 3.7
    1925             : 
    1926             :  @see UpdateFeature()
    1927             : */
    1928             : 
    1929          28 : OGRErr OGRLayer::IUpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
    1930             :                                 const int *panUpdatedFieldsIdx,
    1931             :                                 int nUpdatedGeomFieldsCount,
    1932             :                                 const int *panUpdatedGeomFieldsIdx,
    1933             :                                 bool bUpdateStyleString)
    1934             : {
    1935          28 :     if (!TestCapability(OLCRandomWrite))
    1936           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    1937             : 
    1938             :     auto poFeatureExisting =
    1939          56 :         std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID()));
    1940          28 :     if (!poFeatureExisting)
    1941           1 :         return OGRERR_NON_EXISTING_FEATURE;
    1942             : 
    1943          52 :     for (int i = 0; i < nUpdatedFieldsCount; ++i)
    1944             :     {
    1945          25 :         poFeatureExisting->SetField(
    1946          25 :             panUpdatedFieldsIdx[i],
    1947          25 :             poFeature->GetRawFieldRef(panUpdatedFieldsIdx[i]));
    1948             :     }
    1949          29 :     for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
    1950             :     {
    1951           2 :         poFeatureExisting->SetGeomFieldDirectly(
    1952           2 :             panUpdatedGeomFieldsIdx[i],
    1953           2 :             poFeature->StealGeometry(panUpdatedGeomFieldsIdx[i]));
    1954             :     }
    1955          27 :     if (bUpdateStyleString)
    1956             :     {
    1957           0 :         poFeatureExisting->SetStyleString(poFeature->GetStyleString());
    1958             :     }
    1959          27 :     return ISetFeature(poFeatureExisting.get());
    1960             : }
    1961             : 
    1962             : /************************************************************************/
    1963             : /*                        OGR_L_UpdateFeature()                         */
    1964             : /************************************************************************/
    1965             : 
    1966             : /**
    1967             :  \brief Update (part of) an existing feature.
    1968             : 
    1969             :  This function will update the specified attribute and geometry fields of a
    1970             :  feature to the layer, based on the feature id within the OGRFeature.
    1971             : 
    1972             :  Use OGR_L_TestCapability(OLCRandomWrite) to establish if this layer
    1973             :  supports random access writing via UpdateFeature(). And to know if the
    1974             :  driver supports a dedicated/efficient UpdateFeature() method, test for the
    1975             :  OLCUpdateFeature capability.
    1976             : 
    1977             :  The way unset fields in the provided poFeature are processed is driver dependent:
    1978             :  <ul>
    1979             :  <li>
    1980             :  SQL based drivers which implement SetFeature() through SQL UPDATE will skip
    1981             :  unset fields, and thus the content of the existing feature will be preserved.
    1982             :  </li>
    1983             :  <li>
    1984             :  The shapefile driver will write a NULL value in the DBF file.
    1985             :  </li>
    1986             :  <li>
    1987             :  The GeoJSON driver will take into account unset fields to remove the corresponding
    1988             :  JSON member.
    1989             :  </li>
    1990             :  </ul>
    1991             : 
    1992             :  This method is the same as the C++ method OGRLayer::UpdateFeature().
    1993             : 
    1994             :  To fully replace a feature, see OGR_L_SetFeature()
    1995             : 
    1996             :  Note that after this call the content of hFeat might have changed, and will
    1997             :  *not* reflect the content you would get with OGR_L_GetFeature().
    1998             :  In particular for performance reasons, passed geometries might have been "stolen",
    1999             :  in particular for the default implementation of UpdateFeature() which relies
    2000             :  on GetFeature() + SetFeature().
    2001             : 
    2002             :  @param hLayer handle to the layer to write the feature.
    2003             : 
    2004             :  @param hFeat the feature to update.
    2005             : 
    2006             :  @param nUpdatedFieldsCount number of attribute fields to update. May be 0
    2007             : 
    2008             :  @param panUpdatedFieldsIdx array of nUpdatedFieldsCount values, each between
    2009             :                             0 and GetLayerDefn()->GetFieldCount() - 1, indicating
    2010             :                             which fields of hFeat must be updated in the
    2011             :                             layer.
    2012             : 
    2013             :  @param nUpdatedGeomFieldsCount number of geometry fields to update. May be 0
    2014             : 
    2015             :  @param panUpdatedGeomFieldsIdx array of nUpdatedGeomFieldsCount values, each between
    2016             :                                 0 and GetLayerDefn()->GetGeomFieldCount() - 1, indicating
    2017             :                                 which geometry fields of hFeat must be updated in the
    2018             :                                 layer.
    2019             : 
    2020             :  @param bUpdateStyleString whether the feature style string in the layer should
    2021             :                            be updated with the one of hFeat.
    2022             : 
    2023             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    2024             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    2025             : 
    2026             :  @since GDAL 3.7
    2027             : 
    2028             :  @see OGR_L_UpdateFeature(), OGR_L_CreateFeature(), OGR_L_UpsertFeature()
    2029             : */
    2030             : 
    2031          31 : OGRErr OGR_L_UpdateFeature(OGRLayerH hLayer, OGRFeatureH hFeat,
    2032             :                            int nUpdatedFieldsCount,
    2033             :                            const int *panUpdatedFieldsIdx,
    2034             :                            int nUpdatedGeomFieldsCount,
    2035             :                            const int *panUpdatedGeomFieldsIdx,
    2036             :                            bool bUpdateStyleString)
    2037             : 
    2038             : {
    2039          31 :     VALIDATE_POINTER1(hLayer, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
    2040          31 :     VALIDATE_POINTER1(hFeat, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
    2041             : 
    2042          31 :     return OGRLayer::FromHandle(hLayer)->UpdateFeature(
    2043             :         OGRFeature::FromHandle(hFeat), nUpdatedFieldsCount, panUpdatedFieldsIdx,
    2044          31 :         nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
    2045             : }
    2046             : 
    2047             : /************************************************************************/
    2048             : /*                            CreateField()                             */
    2049             : /************************************************************************/
    2050             : 
    2051             : /**
    2052             : \brief Create a new field on a layer.
    2053             : 
    2054             : You must use this to create new fields
    2055             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2056             : to reflect the new field.  Applications should never modify the OGRFeatureDefn
    2057             : used by a layer directly.
    2058             : 
    2059             : This method should not be called while there are feature objects in existence that
    2060             : were obtained or created with the previous layer definition.
    2061             : 
    2062             : Not all drivers support this method. You can query a layer to check if it supports it
    2063             : with the OLCCreateField capability. Some drivers may only support this method while
    2064             : there are still no features in the layer. When it is supported, the existing features of the
    2065             : backing file/database should be updated accordingly.
    2066             : 
    2067             : Drivers may or may not support not-null constraints. If they support creating
    2068             : fields with not-null constraints, this is generally before creating any feature to the layer.
    2069             : 
    2070             : This function is the same as the C function OGR_L_CreateField().
    2071             : 
    2072             : @param poField field definition to write to disk.
    2073             : @param bApproxOK If TRUE, the field may be created in a slightly different
    2074             : form depending on the limitations of the format driver.
    2075             : 
    2076             : @return OGRERR_NONE on success.
    2077             : */
    2078             : 
    2079          80 : OGRErr OGRLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
    2080             : 
    2081             : {
    2082             :     (void)poField;
    2083             :     (void)bApproxOK;
    2084             : 
    2085          80 :     CPLError(CE_Failure, CPLE_NotSupported,
    2086             :              "CreateField() not supported by this layer.");
    2087             : 
    2088          80 :     return OGRERR_UNSUPPORTED_OPERATION;
    2089             : }
    2090             : 
    2091             : /************************************************************************/
    2092             : /*                         OGR_L_CreateField()                          */
    2093             : /************************************************************************/
    2094             : 
    2095             : /**
    2096             : \brief Create a new field on a layer.
    2097             : 
    2098             : You must use this to create new fields
    2099             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2100             : to reflect the new field.  Applications should never modify the OGRFeatureDefn
    2101             : used by a layer directly.
    2102             : 
    2103             : This function should not be called while there are feature objects in existence that
    2104             : were obtained or created with the previous layer definition.
    2105             : 
    2106             : Not all drivers support this function. You can query a layer to check if it supports it
    2107             : with the OLCCreateField capability. Some drivers may only support this method while
    2108             : there are still no features in the layer. When it is supported, the existing features of the
    2109             : backing file/database should be updated accordingly.
    2110             : 
    2111             : Drivers may or may not support not-null constraints. If they support creating
    2112             : fields with not-null constraints, this is generally before creating any feature to the layer.
    2113             : 
    2114             :  This function is the same as the C++ method OGRLayer::CreateField().
    2115             : 
    2116             :  @param hLayer handle to the layer to write the field definition.
    2117             :  @param hField handle of the field definition to write to disk.
    2118             :  @param bApproxOK If TRUE, the field may be created in a slightly different
    2119             : form depending on the limitations of the format driver.
    2120             : 
    2121             :  @return OGRERR_NONE on success.
    2122             : */
    2123             : 
    2124       78252 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
    2125             : 
    2126             : {
    2127       78252 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
    2128       78252 :     VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
    2129             : 
    2130             : #ifdef OGRAPISPY_ENABLED
    2131       78252 :     if (bOGRAPISpyEnabled)
    2132           6 :         OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
    2133             : #endif
    2134             : 
    2135      156504 :     return OGRLayer::FromHandle(hLayer)->CreateField(
    2136       78252 :         OGRFieldDefn::FromHandle(hField), bApproxOK);
    2137             : }
    2138             : 
    2139             : /************************************************************************/
    2140             : /*                            DeleteField()                             */
    2141             : /************************************************************************/
    2142             : 
    2143             : /**
    2144             : \brief Delete an existing field on a layer.
    2145             : 
    2146             : You must use this to delete existing fields
    2147             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2148             : to reflect the deleted field.  Applications should never modify the OGRFeatureDefn
    2149             : used by a layer directly.
    2150             : 
    2151             : This method should not be called while there are feature objects in existence that
    2152             : were obtained or created with the previous layer definition.
    2153             : 
    2154             : If a OGRFieldDefn* object corresponding to the deleted field has been retrieved
    2155             : from the layer definition before the call to DeleteField(), it must no longer be
    2156             : used after the call to DeleteField(), which will have destroyed it.
    2157             : 
    2158             : Not all drivers support this method. You can query a layer to check if it supports it
    2159             : with the OLCDeleteField capability. Some drivers may only support this method while
    2160             : there are still no features in the layer. When it is supported, the existing features of the
    2161             : backing file/database should be updated accordingly.
    2162             : 
    2163             : This function is the same as the C function OGR_L_DeleteField().
    2164             : 
    2165             : @param iField index of the field to delete.
    2166             : 
    2167             : @return OGRERR_NONE on success.
    2168             : */
    2169             : 
    2170           0 : OGRErr OGRLayer::DeleteField(int iField)
    2171             : 
    2172             : {
    2173             :     (void)iField;
    2174             : 
    2175           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    2176             :              "DeleteField() not supported by this layer.");
    2177             : 
    2178           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    2179             : }
    2180             : 
    2181             : /************************************************************************/
    2182             : /*                         OGR_L_DeleteField()                          */
    2183             : /************************************************************************/
    2184             : 
    2185             : /**
    2186             : \brief Delete an existing field on a layer.
    2187             : 
    2188             : You must use this to delete existing fields
    2189             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2190             : to reflect the deleted field.  Applications should never modify the OGRFeatureDefn
    2191             : used by a layer directly.
    2192             : 
    2193             : This function should not be called while there are feature objects in existence that
    2194             : were obtained or created with the previous layer definition.
    2195             : 
    2196             : If a OGRFieldDefnH object corresponding to the deleted field has been retrieved
    2197             : from the layer definition before the call to DeleteField(), it must no longer be
    2198             : used after the call to DeleteField(), which will have destroyed it.
    2199             : 
    2200             : Not all drivers support this function. You can query a layer to check if it supports it
    2201             : with the OLCDeleteField capability. Some drivers may only support this method while
    2202             : there are still no features in the layer. When it is supported, the existing features of the
    2203             : backing file/database should be updated accordingly.
    2204             : 
    2205             : This function is the same as the C++ method OGRLayer::DeleteField().
    2206             : 
    2207             : @param hLayer handle to the layer.
    2208             : @param iField index of the field to delete.
    2209             : 
    2210             : @return OGRERR_NONE on success.
    2211             : */
    2212             : 
    2213         374 : OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
    2214             : 
    2215             : {
    2216         374 :     VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
    2217             : 
    2218             : #ifdef OGRAPISPY_ENABLED
    2219         374 :     if (bOGRAPISpyEnabled)
    2220           2 :         OGRAPISpy_L_DeleteField(hLayer, iField);
    2221             : #endif
    2222             : 
    2223         374 :     return OGRLayer::FromHandle(hLayer)->DeleteField(iField);
    2224             : }
    2225             : 
    2226             : /************************************************************************/
    2227             : /*                           ReorderFields()                            */
    2228             : /************************************************************************/
    2229             : 
    2230             : /**
    2231             : \brief Reorder all the fields of a layer.
    2232             : 
    2233             : You must use this to reorder existing fields
    2234             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2235             : to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
    2236             : used by a layer directly.
    2237             : 
    2238             : This method should not be called while there are feature objects in existence that
    2239             : were obtained or created with the previous layer definition.
    2240             : 
    2241             : panMap is such that,for each field definition at position i after reordering,
    2242             : its position before reordering was panMap[i].
    2243             : 
    2244             : For example, let suppose the fields were "0","1","2","3","4" initially.
    2245             : ReorderFields([0,2,3,1,4]) will reorder them as "0","2","3","1","4".
    2246             : 
    2247             : Not all drivers support this method. You can query a layer to check if it supports it
    2248             : with the OLCReorderFields capability. Some drivers may only support this method while
    2249             : there are still no features in the layer. When it is supported, the existing features of the
    2250             : backing file/database should be updated accordingly.
    2251             : 
    2252             : This function is the same as the C function OGR_L_ReorderFields().
    2253             : 
    2254             : @param panMap an array of GetLayerDefn()->OGRFeatureDefn::GetFieldCount() elements which
    2255             : is a permutation of [0, GetLayerDefn()->OGRFeatureDefn::GetFieldCount()-1].
    2256             : 
    2257             : @return OGRERR_NONE on success.
    2258             : */
    2259             : 
    2260           0 : OGRErr OGRLayer::ReorderFields(int *panMap)
    2261             : 
    2262             : {
    2263             :     (void)panMap;
    2264             : 
    2265           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    2266             :              "ReorderFields() not supported by this layer.");
    2267             : 
    2268           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    2269             : }
    2270             : 
    2271             : /************************************************************************/
    2272             : /*                        OGR_L_ReorderFields()                         */
    2273             : /************************************************************************/
    2274             : 
    2275             : /**
    2276             : \brief Reorder all the fields of a layer.
    2277             : 
    2278             : You must use this to reorder existing fields
    2279             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2280             : to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
    2281             : used by a layer directly.
    2282             : 
    2283             : This function should not be called while there are feature objects in existence that
    2284             : were obtained or created with the previous layer definition.
    2285             : 
    2286             : panMap is such that,for each field definition at position i after reordering,
    2287             : its position before reordering was panMap[i].
    2288             : 
    2289             : For example, let suppose the fields were "0","1","2","3","4" initially.
    2290             : ReorderFields([0,2,3,1,4]) will reorder them as "0","2","3","1","4".
    2291             : 
    2292             : Not all drivers support this function. You can query a layer to check if it supports it
    2293             : with the OLCReorderFields capability. Some drivers may only support this method while
    2294             : there are still no features in the layer. When it is supported, the existing features of the
    2295             : backing file/database should be updated accordingly.
    2296             : 
    2297             : This function is the same as the C++ method OGRLayer::ReorderFields().
    2298             : 
    2299             : @param hLayer handle to the layer.
    2300             : @param panMap an array of GetLayerDefn()->OGRFeatureDefn::GetFieldCount() elements which
    2301             : is a permutation of [0, GetLayerDefn()->OGRFeatureDefn::GetFieldCount()-1].
    2302             : 
    2303             : @return OGRERR_NONE on success.
    2304             : */
    2305             : 
    2306          43 : OGRErr OGR_L_ReorderFields(OGRLayerH hLayer, int *panMap)
    2307             : 
    2308             : {
    2309          43 :     VALIDATE_POINTER1(hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE);
    2310             : 
    2311             : #ifdef OGRAPISPY_ENABLED
    2312          43 :     if (bOGRAPISpyEnabled)
    2313           2 :         OGRAPISpy_L_ReorderFields(hLayer, panMap);
    2314             : #endif
    2315             : 
    2316          43 :     return OGRLayer::FromHandle(hLayer)->ReorderFields(panMap);
    2317             : }
    2318             : 
    2319             : /************************************************************************/
    2320             : /*                            ReorderField()                            */
    2321             : /************************************************************************/
    2322             : 
    2323             : /**
    2324             : \brief Reorder an existing field on a layer.
    2325             : 
    2326             : This method is a convenience wrapper of ReorderFields() dedicated to move a single field.
    2327             : It is a non-virtual method, so drivers should implement ReorderFields() instead.
    2328             : 
    2329             : You must use this to reorder existing fields
    2330             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2331             : to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
    2332             : used by a layer directly.
    2333             : 
    2334             : This method should not be called while there are feature objects in existence that
    2335             : were obtained or created with the previous layer definition.
    2336             : 
    2337             : The field definition that was at initial position iOldFieldPos will be moved at
    2338             : position iNewFieldPos, and elements between will be shuffled accordingly.
    2339             : 
    2340             : For example, let suppose the fields were "0","1","2","3","4" initially.
    2341             : ReorderField(1, 3) will reorder them as "0","2","3","1","4".
    2342             : 
    2343             : Not all drivers support this method. You can query a layer to check if it supports it
    2344             : with the OLCReorderFields capability. Some drivers may only support this method while
    2345             : there are still no features in the layer. When it is supported, the existing features of the
    2346             : backing file/database should be updated accordingly.
    2347             : 
    2348             : This function is the same as the C function OGR_L_ReorderField().
    2349             : 
    2350             : @param iOldFieldPos previous position of the field to move. Must be in the range [0,GetFieldCount()-1].
    2351             : @param iNewFieldPos new position of the field to move. Must be in the range [0,GetFieldCount()-1].
    2352             : 
    2353             : @return OGRERR_NONE on success.
    2354             : */
    2355             : 
    2356          34 : OGRErr OGRLayer::ReorderField(int iOldFieldPos, int iNewFieldPos)
    2357             : 
    2358             : {
    2359             :     OGRErr eErr;
    2360             : 
    2361          34 :     int nFieldCount = GetLayerDefn()->GetFieldCount();
    2362             : 
    2363          34 :     if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
    2364             :     {
    2365           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    2366           0 :         return OGRERR_FAILURE;
    2367             :     }
    2368          34 :     if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
    2369             :     {
    2370           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    2371           0 :         return OGRERR_FAILURE;
    2372             :     }
    2373          34 :     if (iNewFieldPos == iOldFieldPos)
    2374           0 :         return OGRERR_NONE;
    2375             : 
    2376          34 :     int *panMap = static_cast<int *>(CPLMalloc(sizeof(int) * nFieldCount));
    2377          34 :     if (iOldFieldPos < iNewFieldPos)
    2378             :     {
    2379             :         /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
    2380          15 :         int i = 0;  // Used after for.
    2381          19 :         for (; i < iOldFieldPos; i++)
    2382           4 :             panMap[i] = i;
    2383          40 :         for (; i < iNewFieldPos; i++)
    2384          25 :             panMap[i] = i + 1;
    2385          15 :         panMap[iNewFieldPos] = iOldFieldPos;
    2386          27 :         for (i = iNewFieldPos + 1; i < nFieldCount; i++)
    2387          12 :             panMap[i] = i;
    2388             :     }
    2389             :     else
    2390             :     {
    2391             :         /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
    2392          23 :         for (int i = 0; i < iNewFieldPos; i++)
    2393           4 :             panMap[i] = i;
    2394          19 :         panMap[iNewFieldPos] = iOldFieldPos;
    2395          19 :         int i = iNewFieldPos + 1;  // Used after for.
    2396          67 :         for (; i <= iOldFieldPos; i++)
    2397          48 :             panMap[i] = i - 1;
    2398          31 :         for (; i < nFieldCount; i++)
    2399          12 :             panMap[i] = i;
    2400             :     }
    2401             : 
    2402          34 :     eErr = ReorderFields(panMap);
    2403             : 
    2404          34 :     CPLFree(panMap);
    2405             : 
    2406          34 :     return eErr;
    2407             : }
    2408             : 
    2409             : /************************************************************************/
    2410             : /*                         OGR_L_ReorderField()                         */
    2411             : /************************************************************************/
    2412             : 
    2413             : /**
    2414             : \brief Reorder an existing field on a layer.
    2415             : 
    2416             : This function is a convenience wrapper of OGR_L_ReorderFields() dedicated to move a single field.
    2417             : 
    2418             : You must use this to reorder existing fields
    2419             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2420             : to reflect the reordering of the fields.  Applications should never modify the OGRFeatureDefn
    2421             : used by a layer directly.
    2422             : 
    2423             : This function should not be called while there are feature objects in existence that
    2424             : were obtained or created with the previous layer definition.
    2425             : 
    2426             : The field definition that was at initial position iOldFieldPos will be moved at
    2427             : position iNewFieldPos, and elements between will be shuffled accordingly.
    2428             : 
    2429             : For example, let suppose the fields were "0","1","2","3","4" initially.
    2430             : ReorderField(1, 3) will reorder them as "0","2","3","1","4".
    2431             : 
    2432             : Not all drivers support this function. You can query a layer to check if it supports it
    2433             : with the OLCReorderFields capability. Some drivers may only support this method while
    2434             : there are still no features in the layer. When it is supported, the existing features of the
    2435             : backing file/database should be updated accordingly.
    2436             : 
    2437             : This function is the same as the C++ method OGRLayer::ReorderField().
    2438             : 
    2439             : @param hLayer handle to the layer.
    2440             : @param iOldFieldPos previous position of the field to move. Must be in the range [0,GetFieldCount()-1].
    2441             : @param iNewFieldPos new position of the field to move. Must be in the range [0,GetFieldCount()-1].
    2442             : 
    2443             : @return OGRERR_NONE on success.
    2444             : */
    2445             : 
    2446          34 : OGRErr OGR_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos)
    2447             : 
    2448             : {
    2449          34 :     VALIDATE_POINTER1(hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE);
    2450             : 
    2451             : #ifdef OGRAPISPY_ENABLED
    2452          34 :     if (bOGRAPISpyEnabled)
    2453           2 :         OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
    2454             : #endif
    2455             : 
    2456          34 :     return OGRLayer::FromHandle(hLayer)->ReorderField(iOldFieldPos,
    2457          34 :                                                       iNewFieldPos);
    2458             : }
    2459             : 
    2460             : /************************************************************************/
    2461             : /*                           AlterFieldDefn()                           */
    2462             : /************************************************************************/
    2463             : 
    2464             : /**
    2465             : \brief Alter the definition of an existing field on a layer.
    2466             : 
    2467             : You must use this to alter the definition of an existing field of a real layer.
    2468             : Internally the OGRFeatureDefn for the layer will be updated
    2469             : to reflect the altered field.  Applications should never modify the OGRFeatureDefn
    2470             : used by a layer directly.
    2471             : 
    2472             : This method should not be called while there are feature objects in existence that
    2473             : were obtained or created with the previous layer definition.
    2474             : 
    2475             : Not all drivers support this method. You can query a layer to check if it supports it
    2476             : with the OLCAlterFieldDefn capability. Some drivers may only support this method while
    2477             : there are still no features in the layer. When it is supported, the existing features of the
    2478             : backing file/database should be updated accordingly. Some drivers might also not support
    2479             : all update flags.
    2480             : 
    2481             : This function is the same as the C function OGR_L_AlterFieldDefn().
    2482             : 
    2483             : @param iField index of the field whose definition must be altered.
    2484             : @param poNewFieldDefn new field definition
    2485             : @param nFlagsIn combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG, ALTER_WIDTH_PRECISION_FLAG,
    2486             : ALTER_NULLABLE_FLAG and ALTER_DEFAULT_FLAG
    2487             : to indicate which of the name and/or type and/or width and precision fields and/or nullability from the new field
    2488             : definition must be taken into account.
    2489             : 
    2490             : @return OGRERR_NONE on success.
    2491             : */
    2492             : 
    2493           0 : OGRErr OGRLayer::AlterFieldDefn(int iField, OGRFieldDefn *poNewFieldDefn,
    2494             :                                 int nFlagsIn)
    2495             : 
    2496             : {
    2497             :     (void)iField;
    2498             :     (void)poNewFieldDefn;
    2499             :     (void)nFlagsIn;
    2500           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    2501             :              "AlterFieldDefn() not supported by this layer.");
    2502             : 
    2503           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    2504             : }
    2505             : 
    2506             : /************************************************************************/
    2507             : /*                        OGR_L_AlterFieldDefn()                        */
    2508             : /************************************************************************/
    2509             : 
    2510             : /**
    2511             : \brief Alter the definition of an existing field on a layer.
    2512             : 
    2513             : You must use this to alter the definition of an existing field of a real layer.
    2514             : Internally the OGRFeatureDefn for the layer will be updated
    2515             : to reflect the altered field.  Applications should never modify the OGRFeatureDefn
    2516             : used by a layer directly.
    2517             : 
    2518             : This function should not be called while there are feature objects in existence that
    2519             : were obtained or created with the previous layer definition.
    2520             : 
    2521             : Not all drivers support this function. You can query a layer to check if it supports it
    2522             : with the OLCAlterFieldDefn capability. Some drivers may only support this method while
    2523             : there are still no features in the layer. When it is supported, the existing features of the
    2524             : backing file/database should be updated accordingly. Some drivers might also not support
    2525             : all update flags.
    2526             : 
    2527             : This function is the same as the C++ method OGRLayer::AlterFieldDefn().
    2528             : 
    2529             : @param hLayer handle to the layer.
    2530             : @param iField index of the field whose definition must be altered.
    2531             : @param hNewFieldDefn new field definition
    2532             : @param nFlags combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG, ALTER_WIDTH_PRECISION_FLAG,
    2533             : ALTER_NULLABLE_FLAG and ALTER_DEFAULT_FLAG
    2534             : to indicate which of the name and/or type and/or width and precision fields and/or nullability from the new field
    2535             : definition must be taken into account.
    2536             : 
    2537             : @return OGRERR_NONE on success.
    2538             : */
    2539             : 
    2540         126 : OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
    2541             :                             OGRFieldDefnH hNewFieldDefn, int nFlags)
    2542             : 
    2543             : {
    2544         126 :     VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
    2545         126 :     VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
    2546             :                       OGRERR_INVALID_HANDLE);
    2547             : 
    2548             : #ifdef OGRAPISPY_ENABLED
    2549         126 :     if (bOGRAPISpyEnabled)
    2550           2 :         OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
    2551             : #endif
    2552             : 
    2553         252 :     return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
    2554         126 :         iField, OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags);
    2555             : }
    2556             : 
    2557             : /************************************************************************/
    2558             : /*                         AlterGeomFieldDefn()                         */
    2559             : /************************************************************************/
    2560             : 
    2561             : /**
    2562             : \brief Alter the definition of an existing geometry field on a layer.
    2563             : 
    2564             : You must use this to alter the definition of an existing geometry field of a real layer.
    2565             : Internally the OGRFeatureDefn for the layer will be updated
    2566             : to reflect the altered field.  Applications should never modify the OGRFeatureDefn
    2567             : used by a layer directly.
    2568             : 
    2569             : Note that altering the SRS does *not* cause coordinate reprojection to occur:
    2570             : this is simply a modification of the layer metadata (correcting a wrong SRS
    2571             : definition). No modification to existing geometries will ever be performed,
    2572             : so this method cannot be used to e.g. promote single part geometries to their
    2573             : multipart equivalents.
    2574             : 
    2575             : This method should not be called while there are feature objects in existence that
    2576             : were obtained or created with the previous layer definition.
    2577             : 
    2578             : Not all drivers support this method. You can query a layer to check if it supports it
    2579             : with the OLCAlterGeomFieldDefn capability. Some drivers might not support
    2580             : all update flags. The GDAL_DMD_ALTER_GEOM_FIELD_DEFN_FLAGS driver metadata item
    2581             : can be queried to examine which flags may be supported by a driver.
    2582             : 
    2583             : This function is the same as the C function OGR_L_AlterGeomFieldDefn().
    2584             : 
    2585             : @param iGeomField index of the field whose definition must be altered.
    2586             : @param poNewGeomFieldDefn new field definition
    2587             : @param nFlagsIn combination of ALTER_GEOM_FIELD_DEFN_NAME_FLAG, ALTER_GEOM_FIELD_DEFN_TYPE_FLAG, ALTER_GEOM_FIELD_DEFN_NULLABLE_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_COORD_EPOCH_FLAG
    2588             : to indicate which of the name and/or type and/or nullability and/or SRS and/or coordinate epoch from the new field
    2589             : definition must be taken into account. Or ALTER_GEOM_FIELD_DEFN_ALL_FLAG to update all members.
    2590             : 
    2591             : @return OGRERR_NONE on success.
    2592             : 
    2593             : @since OGR 3.6.0
    2594             : */
    2595             : 
    2596           0 : OGRErr OGRLayer::AlterGeomFieldDefn(int iGeomField,
    2597             :                                     const OGRGeomFieldDefn *poNewGeomFieldDefn,
    2598             :                                     int nFlagsIn)
    2599             : 
    2600             : {
    2601             :     (void)iGeomField;
    2602             :     (void)poNewGeomFieldDefn;
    2603             :     (void)nFlagsIn;
    2604             : 
    2605           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    2606             :              "AlterGeomFieldDefn() not supported by this layer.");
    2607             : 
    2608           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    2609             : }
    2610             : 
    2611             : /************************************************************************/
    2612             : /*                      OGR_L_AlterGeomFieldDefn()                      */
    2613             : /************************************************************************/
    2614             : 
    2615             : /**
    2616             : \brief Alter the definition of an existing geometry field on a layer.
    2617             : 
    2618             : You must use this to alter the definition of an existing geometry field of a real layer.
    2619             : Internally the OGRFeatureDefn for the layer will be updated
    2620             : to reflect the altered field.  Applications should never modify the OGRFeatureDefn
    2621             : used by a layer directly.
    2622             : 
    2623             : Note that altering the SRS does *not* cause coordinate reprojection to occur:
    2624             : this is simply a modification of the layer metadata (correcting a wrong SRS
    2625             : definition). No modification to existing geometries will ever be performed,
    2626             : so this method cannot be used to e.g. promote single part geometries to their
    2627             : multipart equivalents.
    2628             : 
    2629             : This function should not be called while there are feature objects in existence that
    2630             : were obtained or created with the previous layer definition.
    2631             : 
    2632             : Not all drivers support this function. You can query a layer to check if it supports it
    2633             : with the OLCAlterGeomFieldDefn capability. Some drivers might not support
    2634             : all update flags. The GDAL_DMD_ALTER_GEOM_FIELD_DEFN_FLAGS driver metadata item
    2635             : can be queried to examine which flags may be supported by a driver.
    2636             : 
    2637             : This function is the same as the C++ method OGRLayer::AlterFieldDefn().
    2638             : 
    2639             : @param hLayer handle to the layer.
    2640             : @param iGeomField index of the field whose definition must be altered.
    2641             : @param hNewGeomFieldDefn new field definition
    2642             : @param nFlags combination of ALTER_GEOM_FIELD_DEFN_NAME_FLAG, ALTER_GEOM_FIELD_DEFN_TYPE_FLAG, ALTER_GEOM_FIELD_DEFN_NULLABLE_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_FLAG, ALTER_GEOM_FIELD_DEFN_SRS_COORD_EPOCH_FLAG
    2643             : to indicate which of the name and/or type and/or nullability and/or SRS and/or coordinate epoch from the new field
    2644             : definition must be taken into account. Or ALTER_GEOM_FIELD_DEFN_ALL_FLAG to update all members.
    2645             : 
    2646             : @return OGRERR_NONE on success.
    2647             : 
    2648             : @since OGR 3.6.0
    2649             : */
    2650             : 
    2651          33 : OGRErr OGR_L_AlterGeomFieldDefn(OGRLayerH hLayer, int iGeomField,
    2652             :                                 OGRGeomFieldDefnH hNewGeomFieldDefn, int nFlags)
    2653             : 
    2654             : {
    2655          33 :     VALIDATE_POINTER1(hLayer, "OGR_L_AlterGeomFieldDefn",
    2656             :                       OGRERR_INVALID_HANDLE);
    2657          33 :     VALIDATE_POINTER1(hNewGeomFieldDefn, "OGR_L_AlterGeomFieldDefn",
    2658             :                       OGRERR_INVALID_HANDLE);
    2659             : 
    2660          66 :     return OGRLayer::FromHandle(hLayer)->AlterGeomFieldDefn(
    2661             :         iGeomField,
    2662             :         const_cast<const OGRGeomFieldDefn *>(
    2663          33 :             OGRGeomFieldDefn::FromHandle(hNewGeomFieldDefn)),
    2664          33 :         nFlags);
    2665             : }
    2666             : 
    2667             : /************************************************************************/
    2668             : /*                          CreateGeomField()                           */
    2669             : /************************************************************************/
    2670             : 
    2671             : /**
    2672             : \brief Create a new geometry field on a layer.
    2673             : 
    2674             : You must use this to create new geometry fields
    2675             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2676             : to reflect the new field.  Applications should never modify the OGRFeatureDefn
    2677             : used by a layer directly.
    2678             : 
    2679             : This method should not be called while there are feature objects in existence that
    2680             : were obtained or created with the previous layer definition.
    2681             : 
    2682             : Not all drivers support this method. You can query a layer to check if it supports it
    2683             : with the OLCCreateGeomField capability. Some drivers may only support this method while
    2684             : there are still no features in the layer. When it is supported, the existing features of the
    2685             : backing file/database should be updated accordingly.
    2686             : 
    2687             : Drivers may or may not support not-null constraints. If they support creating
    2688             : fields with not-null constraints, this is generally before creating any feature to the layer.
    2689             : 
    2690             : This function is the same as the C function OGR_L_CreateGeomField().
    2691             : 
    2692             : @param poField geometry field definition to write to disk.
    2693             : @param bApproxOK If TRUE, the field may be created in a slightly different
    2694             : form depending on the limitations of the format driver.
    2695             : 
    2696             : @return OGRERR_NONE on success.
    2697             : */
    2698             : 
    2699           0 : OGRErr OGRLayer::CreateGeomField(const OGRGeomFieldDefn *poField, int bApproxOK)
    2700             : 
    2701             : {
    2702             :     (void)poField;
    2703             :     (void)bApproxOK;
    2704             : 
    2705           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    2706             :              "CreateGeomField() not supported by this layer.");
    2707             : 
    2708           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    2709             : }
    2710             : 
    2711             : /************************************************************************/
    2712             : /*                       OGR_L_CreateGeomField()                        */
    2713             : /************************************************************************/
    2714             : 
    2715             : /**
    2716             : \brief Create a new geometry field on a layer.
    2717             : 
    2718             : You must use this to create new geometry fields
    2719             : on a real layer. Internally the OGRFeatureDefn for the layer will be updated
    2720             : to reflect the new field.  Applications should never modify the OGRFeatureDefn
    2721             : used by a layer directly.
    2722             : 
    2723             : This function should not be called while there are feature objects in existence that
    2724             : were obtained or created with the previous layer definition.
    2725             : 
    2726             : Not all drivers support this function. You can query a layer to check if it supports it
    2727             : with the OLCCreateField capability. Some drivers may only support this method while
    2728             : there are still no features in the layer. When it is supported, the existing features of the
    2729             : backing file/database should be updated accordingly.
    2730             : 
    2731             : Drivers may or may not support not-null constraints. If they support creating
    2732             : fields with not-null constraints, this is generally before creating any feature to the layer.
    2733             : 
    2734             :  This function is the same as the C++ method OGRLayer::CreateField().
    2735             : 
    2736             :  @param hLayer handle to the layer to write the field definition.
    2737             :  @param hField handle of the geometry field definition to write to disk.
    2738             :  @param bApproxOK If TRUE, the field may be created in a slightly different
    2739             : form depending on the limitations of the format driver.
    2740             : 
    2741             :  @return OGRERR_NONE on success.
    2742             : */
    2743             : 
    2744         147 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
    2745             :                              int bApproxOK)
    2746             : 
    2747             : {
    2748         147 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
    2749         147 :     VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
    2750             : 
    2751             : #ifdef OGRAPISPY_ENABLED
    2752         147 :     if (bOGRAPISpyEnabled)
    2753           2 :         OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
    2754             : #endif
    2755             : 
    2756         294 :     return OGRLayer::FromHandle(hLayer)->CreateGeomField(
    2757         147 :         OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
    2758             : }
    2759             : 
    2760             : /************************************************************************/
    2761             : /*                          StartTransaction()                          */
    2762             : /************************************************************************/
    2763             : 
    2764             : /**
    2765             :  \brief For datasources which support transactions, StartTransaction creates a transaction.
    2766             : 
    2767             :  If starting the transaction fails, will return
    2768             :  OGRERR_FAILURE. Datasources which do not support transactions will
    2769             :  always return OGRERR_NONE.
    2770             : 
    2771             :  Use of this API is discouraged when the dataset offers
    2772             :  dataset level transaction with GDALDataset::StartTransaction(). The reason is
    2773             :  that most drivers can only offer transactions at dataset level, and not layer level.
    2774             :  Very few drivers really support transactions at layer scope.
    2775             : 
    2776             :  This function is the same as the C function OGR_L_StartTransaction().
    2777             : 
    2778             :  @return OGRERR_NONE on success.
    2779             : */
    2780             : 
    2781         889 : OGRErr OGRLayer::StartTransaction()
    2782             : 
    2783             : {
    2784         889 :     return OGRERR_NONE;
    2785             : }
    2786             : 
    2787             : /************************************************************************/
    2788             : /*                       OGR_L_StartTransaction()                       */
    2789             : /************************************************************************/
    2790             : 
    2791             : /**
    2792             :  \brief For datasources which support transactions, StartTransaction creates a transaction.
    2793             : 
    2794             :  If starting the transaction fails, will return
    2795             :  OGRERR_FAILURE. Datasources which do not support transactions will
    2796             :  always return OGRERR_NONE.
    2797             : 
    2798             :  Use of this API is discouraged when the dataset offers
    2799             :  dataset level transaction with GDALDataset::StartTransaction(). The reason is
    2800             :  that most drivers can only offer transactions at dataset level, and not layer level.
    2801             :  Very few drivers really support transactions at layer scope.
    2802             : 
    2803             :  This function is the same as the C++ method OGRLayer::StartTransaction().
    2804             : 
    2805             :  @param hLayer handle to the layer
    2806             : 
    2807             :  @return OGRERR_NONE on success.
    2808             : 
    2809             : */
    2810             : 
    2811         161 : OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
    2812             : 
    2813             : {
    2814         161 :     VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
    2815             : 
    2816             : #ifdef OGRAPISPY_ENABLED
    2817         161 :     if (bOGRAPISpyEnabled)
    2818           2 :         OGRAPISpy_L_StartTransaction(hLayer);
    2819             : #endif
    2820             : 
    2821         161 :     return OGRLayer::FromHandle(hLayer)->StartTransaction();
    2822             : }
    2823             : 
    2824             : /************************************************************************/
    2825             : /*                         CommitTransaction()                          */
    2826             : /************************************************************************/
    2827             : 
    2828             : /**
    2829             :  \brief For datasources which support transactions, CommitTransaction commits a transaction.
    2830             : 
    2831             :  If no transaction is active, or the commit fails, will return
    2832             :  OGRERR_FAILURE. Datasources which do not support transactions will
    2833             :  always return OGRERR_NONE.
    2834             : 
    2835             :  This function is the same as the C function OGR_L_CommitTransaction().
    2836             : 
    2837             :  @return OGRERR_NONE on success.
    2838             : */
    2839             : 
    2840         839 : OGRErr OGRLayer::CommitTransaction()
    2841             : 
    2842             : {
    2843         839 :     return OGRERR_NONE;
    2844             : }
    2845             : 
    2846             : /************************************************************************/
    2847             : /*                      OGR_L_CommitTransaction()                       */
    2848             : /************************************************************************/
    2849             : 
    2850             : /**
    2851             :  \brief For datasources which support transactions, CommitTransaction commits a transaction.
    2852             : 
    2853             :  If no transaction is active, or the commit fails, will return
    2854             :  OGRERR_FAILURE. Datasources which do not support transactions will
    2855             :  always return OGRERR_NONE.
    2856             : 
    2857             :  This function is the same as the C function OGR_L_CommitTransaction().
    2858             : 
    2859             :  @return OGRERR_NONE on success.
    2860             : */
    2861             : 
    2862         141 : OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
    2863             : 
    2864             : {
    2865         141 :     VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
    2866             : 
    2867             : #ifdef OGRAPISPY_ENABLED
    2868         141 :     if (bOGRAPISpyEnabled)
    2869           2 :         OGRAPISpy_L_CommitTransaction(hLayer);
    2870             : #endif
    2871             : 
    2872         141 :     return OGRLayer::FromHandle(hLayer)->CommitTransaction();
    2873             : }
    2874             : 
    2875             : /************************************************************************/
    2876             : /*                        RollbackTransaction()                         */
    2877             : /************************************************************************/
    2878             : 
    2879             : /**
    2880             :  \brief For datasources which support transactions, RollbackTransaction will roll back a datasource to its state before the start of the current transaction.
    2881             :  If no transaction is active, or the rollback fails, will return
    2882             :  OGRERR_FAILURE. Datasources which do not support transactions will
    2883             :  always return OGRERR_NONE.
    2884             : 
    2885             :  This function is the same as the C function OGR_L_RollbackTransaction().
    2886             : 
    2887             : 
    2888             :  OGRFeature* instances acquired or created between the StartTransaction() and RollbackTransaction() should
    2889             :  be destroyed before RollbackTransaction() if the field structure has been modified during the transaction.
    2890             : 
    2891             :  In particular, the following is invalid:
    2892             : 
    2893             :  \code
    2894             :  lyr->StartTransaction();
    2895             :  lyr->DeleteField(...);
    2896             :  f = new OGRFeature(lyr->GetLayerDefn());
    2897             :  lyr->RollbackTransaction();
    2898             :  // f is in a inconsistent state at this point, given its array of fields doesn't match
    2899             :  // the updated layer definition, and thus it cannot even be safely deleted !
    2900             :  \endcode
    2901             : 
    2902             :  Instead, the feature should be destroyed before the rollback:
    2903             : 
    2904             :  \code
    2905             :  lyr->StartTransaction();
    2906             :  lyr->DeleteField(...);
    2907             :  f = new OGRFeature(lyr->GetLayerDefn());
    2908             :  ...
    2909             :  delete f;
    2910             :  \endcode
    2911             : 
    2912             :  @return OGRERR_NONE on success.
    2913             : */
    2914             : 
    2915          53 : OGRErr OGRLayer::RollbackTransaction()
    2916             : 
    2917             : {
    2918          53 :     return OGRERR_UNSUPPORTED_OPERATION;
    2919             : }
    2920             : 
    2921             : /************************************************************************/
    2922             : /*                     OGR_L_RollbackTransaction()                      */
    2923             : /************************************************************************/
    2924             : 
    2925             : /**
    2926             :  \brief For datasources which support transactions, RollbackTransaction will roll back a datasource to its state before the start of the current transaction.
    2927             :  If no transaction is active, or the rollback fails, will return
    2928             :  OGRERR_FAILURE. Datasources which do not support transactions will
    2929             :  always return OGRERR_NONE.
    2930             : 
    2931             :  This function is the same as the C++ method OGRLayer::RollbackTransaction().
    2932             : 
    2933             :  @param hLayer handle to the layer
    2934             : 
    2935             :  @return OGRERR_NONE on success.
    2936             : */
    2937             : 
    2938          26 : OGRErr OGR_L_RollbackTransaction(OGRLayerH hLayer)
    2939             : 
    2940             : {
    2941          26 :     VALIDATE_POINTER1(hLayer, "OGR_L_RollbackTransaction",
    2942             :                       OGRERR_INVALID_HANDLE);
    2943             : 
    2944             : #ifdef OGRAPISPY_ENABLED
    2945          26 :     if (bOGRAPISpyEnabled)
    2946           2 :         OGRAPISpy_L_RollbackTransaction(hLayer);
    2947             : #endif
    2948             : 
    2949          26 :     return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
    2950             : }
    2951             : 
    2952             : /************************************************************************/
    2953             : /*                       OGRLayer::GetLayerDefn()                       */
    2954             : /************************************************************************/
    2955             : 
    2956             : /**
    2957             :  \fn OGRFeatureDefn *OGRLayer::GetLayerDefn();
    2958             : 
    2959             :  \brief Fetch the schema information for this layer.
    2960             : 
    2961             :  The returned OGRFeatureDefn is owned by the OGRLayer, and should not be
    2962             :  modified or freed by the application.  It encapsulates the attribute schema
    2963             :  of the features of the layer.
    2964             : 
    2965             :  This method is the same as the C function OGR_L_GetLayerDefn().
    2966             : 
    2967             :  @return feature definition.
    2968             : */
    2969             : 
    2970             : /**
    2971             :  \fn const OGRFeatureDefn *OGRLayer::GetLayerDefn() const;
    2972             : 
    2973             :  \brief Fetch the schema information for this layer.
    2974             : 
    2975             :  The returned OGRFeatureDefn is owned by the OGRLayer, and should not be
    2976             :  modified or freed by the application.  It encapsulates the attribute schema
    2977             :  of the features of the layer.
    2978             : 
    2979             :  Note that even if this method is const, there is no guarantee it can be
    2980             :  safely called by concurrent threads on the same GDALDataset object.
    2981             : 
    2982             :  This method is the same as the C function OGR_L_GetLayerDefn().
    2983             : 
    2984             :  @return feature definition.
    2985             : 
    2986             :  @since 3.12
    2987             : */
    2988             : 
    2989             : /************************************************************************/
    2990             : /*                         OGR_L_GetLayerDefn()                         */
    2991             : /************************************************************************/
    2992             : 
    2993             : /**
    2994             :  \brief Fetch the schema information for this layer.
    2995             : 
    2996             :  The returned handle to the OGRFeatureDefn is owned by the OGRLayer,
    2997             :  and should not be modified or freed by the application.  It encapsulates
    2998             :  the attribute schema of the features of the layer.
    2999             : 
    3000             :  This function is the same as the C++ method OGRLayer::GetLayerDefn().
    3001             : 
    3002             :  @param hLayer handle to the layer to get the schema information.
    3003             :  @return a handle to the feature definition.
    3004             : 
    3005             : */
    3006      135030 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
    3007             : 
    3008             : {
    3009      135030 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
    3010             : 
    3011             : #ifdef OGRAPISPY_ENABLED
    3012      135030 :     if (bOGRAPISpyEnabled)
    3013          15 :         OGRAPISpy_L_GetLayerDefn(hLayer);
    3014             : #endif
    3015             : 
    3016      135030 :     return OGRFeatureDefn::ToHandle(
    3017      135030 :         OGRLayer::FromHandle(hLayer)->GetLayerDefn());
    3018             : }
    3019             : 
    3020             : /************************************************************************/
    3021             : /*                        OGR_L_FindFieldIndex()                        */
    3022             : /************************************************************************/
    3023             : 
    3024             : /**
    3025             :  \brief Find the index of field in a layer.
    3026             : 
    3027             :  The returned number is the index of the field in the layers, or -1 if the
    3028             :  field doesn't exist.
    3029             : 
    3030             :  If bExactMatch is set to FALSE and the field doesn't exist in the given form
    3031             :  the driver might apply some changes to make it match, like those it might do
    3032             :  if the layer was created (eg. like LAUNDER in the OCI driver).
    3033             : 
    3034             :  This method is the same as the C++ method OGRLayer::FindFieldIndex().
    3035             : 
    3036             :  @return field index, or -1 if the field doesn't exist
    3037             : */
    3038             : 
    3039           2 : int OGR_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
    3040             :                          int bExactMatch)
    3041             : 
    3042             : {
    3043           2 :     VALIDATE_POINTER1(hLayer, "OGR_L_FindFieldIndex", -1);
    3044             : 
    3045             : #ifdef OGRAPISPY_ENABLED
    3046           2 :     if (bOGRAPISpyEnabled)
    3047           2 :         OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
    3048             : #endif
    3049             : 
    3050           4 :     return OGRLayer::FromHandle(hLayer)->FindFieldIndex(pszFieldName,
    3051           2 :                                                         bExactMatch);
    3052             : }
    3053             : 
    3054             : /************************************************************************/
    3055             : /*                           FindFieldIndex()                           */
    3056             : /************************************************************************/
    3057             : 
    3058             : /**
    3059             :  \brief Find the index of field in the layer.
    3060             : 
    3061             :  The returned number is the index of the field in the layers, or -1 if the
    3062             :  field doesn't exist.
    3063             : 
    3064             :  If bExactMatch is set to FALSE and the field doesn't exist in the given form
    3065             :  the driver might apply some changes to make it match, like those it might do
    3066             :  if the layer was created (eg. like LAUNDER in the OCI driver).
    3067             : 
    3068             :  This method is the same as the C function OGR_L_FindFieldIndex().
    3069             : 
    3070             :  @return field index, or -1 if the field doesn't exist
    3071             : */
    3072             : 
    3073          83 : int OGRLayer::FindFieldIndex(const char *pszFieldName,
    3074             :                              CPL_UNUSED int bExactMatch)
    3075             : {
    3076          83 :     return GetLayerDefn()->GetFieldIndex(pszFieldName);
    3077             : }
    3078             : 
    3079             : /************************************************************************/
    3080             : /*                           GetSpatialRef()                            */
    3081             : /************************************************************************/
    3082             : 
    3083             : /**
    3084             :  \brief Fetch the spatial reference system for this layer.
    3085             : 
    3086             :  The returned object is owned by the OGRLayer and should not be modified
    3087             :  or freed by the application.
    3088             : 
    3089             :  Note that even if this method is const (since GDAL 3.12), there is no guarantee
    3090             :  it can be safely called by concurrent threads on the same GDALDataset object.
    3091             : 
    3092             :  Several geometry fields can be associated to a
    3093             :  feature definition. Each geometry field can have its own spatial reference
    3094             :  system, which is returned by OGRGeomFieldDefn::GetSpatialRef().
    3095             :  OGRLayer::GetSpatialRef() is equivalent to
    3096             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(0)->GetSpatialRef()
    3097             : 
    3098             :  This method is the same as the C function OGR_L_GetSpatialRef().
    3099             : 
    3100             :  @return spatial reference, or NULL if there isn't one.
    3101             : */
    3102             : 
    3103      441062 : const OGRSpatialReference *OGRLayer::GetSpatialRef() const
    3104             : {
    3105      441062 :     const auto poLayerDefn = GetLayerDefn();
    3106      441062 :     if (poLayerDefn->GetGeomFieldCount() > 0)
    3107             :         return const_cast<OGRSpatialReference *>(
    3108      440459 :             poLayerDefn->GetGeomFieldDefn(0)->GetSpatialRef());
    3109             :     else
    3110         603 :         return nullptr;
    3111             : }
    3112             : 
    3113             : /************************************************************************/
    3114             : /*                        OGR_L_GetSpatialRef()                         */
    3115             : /************************************************************************/
    3116             : 
    3117             : /**
    3118             :  \brief Fetch the spatial reference system for this layer.
    3119             : 
    3120             :  The returned object is owned by the OGRLayer and should not be modified
    3121             :  or freed by the application.
    3122             : 
    3123             :  This function is the same as the C++ method OGRLayer::GetSpatialRef().
    3124             : 
    3125             :  @param hLayer handle to the layer to get the spatial reference from.
    3126             :  @return spatial reference, or NULL if there isn't one.
    3127             : */
    3128             : 
    3129        1146 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
    3130             : 
    3131             : {
    3132        1146 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
    3133             : 
    3134             : #ifdef OGRAPISPY_ENABLED
    3135        1146 :     if (bOGRAPISpyEnabled)
    3136           2 :         OGRAPISpy_L_GetSpatialRef(hLayer);
    3137             : #endif
    3138             : 
    3139        1146 :     return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
    3140        1146 :         OGRLayer::FromHandle(hLayer)->GetSpatialRef()));
    3141             : }
    3142             : 
    3143             : /************************************************************************/
    3144             : /*                      OGRLayer::TestCapability()                      */
    3145             : /************************************************************************/
    3146             : 
    3147             : /**
    3148             :  \fn int OGRLayer::TestCapability( const char * pszCap ) const;
    3149             : 
    3150             :  \brief Test if this layer supported the named capability.
    3151             : 
    3152             :  The capability codes that can be tested are represented as strings, but
    3153             :  \#defined constants exists to ensure correct spelling.  Specific layer
    3154             :  types may implement class specific capabilities, but this can't generally
    3155             :  be discovered by the caller. <p>
    3156             : 
    3157             : <ul>
    3158             : 
    3159             :  <li> <b>OLCRandomRead</b> / "RandomRead": TRUE if the GetFeature() method
    3160             : is implemented in an optimized way for this layer, as opposed to the default
    3161             : implementation using ResetReading() and GetNextFeature() to find the requested
    3162             : feature id.<p>
    3163             : 
    3164             :  <li> <b>OLCSequentialWrite</b> / "SequentialWrite": TRUE if the
    3165             : CreateFeature() method works for this layer.  Note this means that this
    3166             : particular layer is writable.  The same OGRLayer class may return FALSE
    3167             : for other layer instances that are effectively read-only.<p>
    3168             : 
    3169             :  <li> <b>OLCRandomWrite</b> / "RandomWrite": TRUE if the SetFeature() method
    3170             : is operational on this layer.  Note this means that this
    3171             : particular layer is writable.  The same OGRLayer class may return FALSE
    3172             : for other layer instances that are effectively read-only.<p>
    3173             : 
    3174             :  <li> <b>OLCUpsertFeature</b> / "UpsertFeature": TRUE if the UpsertFeature()
    3175             : method is operational on this layer.  Note this means that this
    3176             : particular layer is writable.  The same OGRLayer class may return FALSE
    3177             : for other layer instances that are effectively read-only.<p>
    3178             : 
    3179             :  <li> <b>OLCFastSpatialFilter</b> / "FastSpatialFilter": TRUE if this layer
    3180             : implements spatial filtering efficiently.  Layers that effectively read all
    3181             : features, and test them with the OGRFeature intersection methods should
    3182             : return FALSE.  This can be used as a clue by the application whether it
    3183             : should build and maintain its own spatial index for features in this layer.<p>
    3184             : 
    3185             :  <li> <b>OLCFastFeatureCount</b> / "FastFeatureCount":
    3186             : TRUE if this layer can return a feature
    3187             : count (via GetFeatureCount()) efficiently. i.e. without counting
    3188             : the features.  In some cases this will return TRUE until a spatial filter is
    3189             : installed after which it will return FALSE.<p>
    3190             : 
    3191             :  <li> <b>OLCFastGetExtent</b> / "FastGetExtent":
    3192             : TRUE if this layer can return its data extent (via GetExtent())
    3193             : efficiently, i.e. without scanning all the features.  In some cases this
    3194             : will return TRUE until a spatial filter is installed after which it will
    3195             : return FALSE.<p>
    3196             : 
    3197             :  <li> <b>OLCFastSetNextByIndex</b> / "FastSetNextByIndex":
    3198             : TRUE if this layer can perform the SetNextByIndex() call efficiently, otherwise
    3199             : FALSE.<p>
    3200             : 
    3201             :  <li> <b>OLCCreateField</b> / "CreateField": TRUE if this layer can create
    3202             : new fields on the current layer using CreateField(), otherwise FALSE.<p>
    3203             : 
    3204             :  <li> <b>OLCCreateGeomField</b> / "CreateGeomField": (GDAL >= 1.11) TRUE if this layer can create
    3205             : new geometry fields on the current layer using CreateGeomField(), otherwise FALSE.<p>
    3206             : 
    3207             :  <li> <b>OLCDeleteField</b> / "DeleteField": TRUE if this layer can delete
    3208             : existing fields on the current layer using DeleteField(), otherwise FALSE.<p>
    3209             : 
    3210             :  <li> <b>OLCReorderFields</b> / "ReorderFields": TRUE if this layer can reorder
    3211             : existing fields on the current layer using ReorderField() or ReorderFields(), otherwise FALSE.<p>
    3212             : 
    3213             :  <li> <b>OLCAlterFieldDefn</b> / "AlterFieldDefn": TRUE if this layer can alter
    3214             : the definition of an existing field on the current layer using AlterFieldDefn(), otherwise FALSE.<p>
    3215             : 
    3216             :  <li> <b>OLCAlterGeomFieldDefn</b> / "AlterGeomFieldDefn": TRUE if this layer can alter
    3217             : the definition of an existing geometry field on the current layer using AlterGeomFieldDefn(), otherwise FALSE.<p>
    3218             : 
    3219             :  <li> <b>OLCDeleteFeature</b> / "DeleteFeature": TRUE if the DeleteFeature()
    3220             : method is supported on this layer, otherwise FALSE.<p>
    3221             : 
    3222             :  <li> <b>OLCStringsAsUTF8</b> / "StringsAsUTF8": TRUE if values of OFTString
    3223             : fields are assured to be in UTF-8 format.  If FALSE the encoding of fields
    3224             : is uncertain, though it might still be UTF-8.<p>
    3225             : 
    3226             : <li> <b>OLCTransactions</b> / "Transactions": TRUE if the StartTransaction(),
    3227             : CommitTransaction() and RollbackTransaction() methods work in a meaningful way,
    3228             : otherwise FALSE.<p>
    3229             : 
    3230             : <li> <b>OLCIgnoreFields</b> / "IgnoreFields": TRUE if fields, geometry and style
    3231             : will be omitted when fetching features as set by SetIgnoredFields() method.
    3232             : 
    3233             : <li> <b>OLCCurveGeometries</b> / "CurveGeometries": TRUE if this layer supports
    3234             : writing curve geometries or may return such geometries.
    3235             : 
    3236             : <p>
    3237             : 
    3238             : </ul>
    3239             : 
    3240             :  This method is the same as the C function OGR_L_TestCapability().
    3241             : 
    3242             :  @param pszCap the name of the capability to test.
    3243             : 
    3244             :  @return TRUE if the layer has the requested capability, or FALSE otherwise.
    3245             : OGRLayers will return FALSE for any unrecognized capabilities.<p>
    3246             : 
    3247             : */
    3248             : 
    3249             : /************************************************************************/
    3250             : /*                        OGR_L_TestCapability()                        */
    3251             : /************************************************************************/
    3252             : 
    3253             : /**
    3254             :  \brief Test if this layer supported the named capability.
    3255             : 
    3256             :  The capability codes that can be tested are represented as strings, but
    3257             :  \#defined constants exists to ensure correct spelling.  Specific layer
    3258             :  types may implement class specific capabilities, but this can't generally
    3259             :  be discovered by the caller. <p>
    3260             : 
    3261             : <ul>
    3262             : 
    3263             :  <li> <b>OLCRandomRead</b> / "RandomRead": TRUE if the GetFeature() method
    3264             : is implemented in an optimized way for this layer, as opposed to the default
    3265             : implementation using ResetReading() and GetNextFeature() to find the requested
    3266             : feature id.<p>
    3267             : 
    3268             :  <li> <b>OLCSequentialWrite</b> / "SequentialWrite": TRUE if the
    3269             : CreateFeature() method works for this layer.  Note this means that this
    3270             : particular layer is writable.  The same OGRLayer class may return FALSE
    3271             : for other layer instances that are effectively read-only.<p>
    3272             : 
    3273             :  <li> <b>OLCRandomWrite</b> / "RandomWrite": TRUE if the SetFeature() method
    3274             : is operational on this layer.  Note this means that this
    3275             : particular layer is writable.  The same OGRLayer class may return FALSE
    3276             : for other layer instances that are effectively read-only.<p>
    3277             : 
    3278             :  <li> <b>OLCUpsertFeature</b> / "UpsertFeature": TRUE if the UpsertFeature()
    3279             : method is operational on this layer.  Note this means that this
    3280             : particular layer is writable.  The same OGRLayer class may return FALSE
    3281             : for other layer instances that are effectively read-only.<p>
    3282             : 
    3283             :  <li> <b>OLCFastSpatialFilter</b> / "FastSpatialFilter": TRUE if this layer
    3284             : implements spatial filtering efficiently.  Layers that effectively read all
    3285             : features, and test them with the OGRFeature intersection methods should
    3286             : return FALSE.  This can be used as a clue by the application whether it
    3287             : should build and maintain its own spatial index for features in this
    3288             : layer.<p>
    3289             : 
    3290             :  <li> <b>OLCFastFeatureCount</b> / "FastFeatureCount":
    3291             : TRUE if this layer can return a feature
    3292             : count (via OGR_L_GetFeatureCount()) efficiently, i.e. without counting
    3293             : the features.  In some cases this will return TRUE until a spatial filter is
    3294             : installed after which it will return FALSE.<p>
    3295             : 
    3296             :  <li> <b>OLCFastGetExtent</b> / "FastGetExtent":
    3297             : TRUE if this layer can return its data extent (via OGR_L_GetExtent())
    3298             : efficiently, i.e. without scanning all the features.  In some cases this
    3299             : will return TRUE until a spatial filter is installed after which it will
    3300             : return FALSE.<p>
    3301             : 
    3302             :  <li> <b>OLCFastSetNextByIndex</b> / "FastSetNextByIndex":
    3303             : TRUE if this layer can perform the SetNextByIndex() call efficiently, otherwise
    3304             : FALSE.<p>
    3305             : 
    3306             :  <li> <b>OLCCreateField</b> / "CreateField": TRUE if this layer can create
    3307             : new fields on the current layer using CreateField(), otherwise FALSE.<p>
    3308             : 
    3309             :  <li> <b>OLCCreateGeomField</b> / "CreateGeomField": (GDAL >= 1.11) TRUE if this layer can create
    3310             : new geometry fields on the current layer using CreateGeomField(), otherwise FALSE.<p>
    3311             : 
    3312             :  <li> <b>OLCDeleteField</b> / "DeleteField": TRUE if this layer can delete
    3313             : existing fields on the current layer using DeleteField(), otherwise FALSE.<p>
    3314             : 
    3315             :  <li> <b>OLCReorderFields</b> / "ReorderFields": TRUE if this layer can reorder
    3316             : existing fields on the current layer using ReorderField() or ReorderFields(), otherwise FALSE.<p>
    3317             : 
    3318             :  <li> <b>OLCAlterFieldDefn</b> / "AlterFieldDefn": TRUE if this layer can alter
    3319             : the definition of an existing field on the current layer using AlterFieldDefn(), otherwise FALSE.<p>
    3320             : 
    3321             :  <li> <b>OLCAlterGeomFieldDefn</b> / "AlterGeomFieldDefn": TRUE if this layer can alter
    3322             : the definition of an existing geometry field on the current layer using AlterGeomFieldDefn(), otherwise FALSE.<p>
    3323             : 
    3324             :  <li> <b>OLCDeleteFeature</b> / "DeleteFeature": TRUE if the DeleteFeature()
    3325             : method is supported on this layer, otherwise FALSE.<p>
    3326             : 
    3327             :  <li> <b>OLCStringsAsUTF8</b> / "StringsAsUTF8": TRUE if values of OFTString
    3328             : fields are assured to be in UTF-8 format.  If FALSE the encoding of fields
    3329             : is uncertain, though it might still be UTF-8.<p>
    3330             : 
    3331             : <li> <b>OLCTransactions</b> / "Transactions": TRUE if the StartTransaction(),
    3332             : CommitTransaction() and RollbackTransaction() methods work in a meaningful way,
    3333             : otherwise FALSE.<p>
    3334             : 
    3335             : <li> <b>OLCCurveGeometries</b> / "CurveGeometries": TRUE if this layer supports
    3336             : writing curve geometries or may return such geometries.
    3337             : 
    3338             : <p>
    3339             : 
    3340             : </ul>
    3341             : 
    3342             :  This function is the same as the C++ method OGRLayer::TestCapability().
    3343             : 
    3344             :  @param hLayer handle to the layer to get the capability from.
    3345             :  @param pszCap the name of the capability to test.
    3346             : 
    3347             :  @return TRUE if the layer has the requested capability, or FALSE otherwise.
    3348             : OGRLayers will return FALSE for any unrecognized capabilities.<p>
    3349             : 
    3350             : */
    3351             : 
    3352         996 : int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
    3353             : 
    3354             : {
    3355         996 :     VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
    3356         996 :     VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
    3357             : 
    3358             : #ifdef OGRAPISPY_ENABLED
    3359         996 :     if (bOGRAPISpyEnabled)
    3360           2 :         OGRAPISpy_L_TestCapability(hLayer, pszCap);
    3361             : #endif
    3362             : 
    3363         996 :     return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
    3364             : }
    3365             : 
    3366             : /************************************************************************/
    3367             : /*                          GetSpatialFilter()                          */
    3368             : /************************************************************************/
    3369             : 
    3370             : /**
    3371             :  \brief This method returns the current spatial filter for this layer.
    3372             : 
    3373             :  The returned pointer is to an internally owned object, and should not
    3374             :  be altered or deleted by the caller.
    3375             : 
    3376             :  This method is the same as the C function OGR_L_GetSpatialFilter().
    3377             : 
    3378             :  @return spatial filter geometry.
    3379             :  */
    3380             : 
    3381         482 : OGRGeometry *OGRLayer::GetSpatialFilter()
    3382             : 
    3383             : {
    3384         482 :     return m_poFilterGeom;
    3385             : }
    3386             : 
    3387             : /************************************************************************/
    3388             : /*                       OGR_L_GetSpatialFilter()                       */
    3389             : /************************************************************************/
    3390             : 
    3391             : /**
    3392             :  \brief This function returns the current spatial filter for this layer.
    3393             : 
    3394             :  The returned pointer is to an internally owned object, and should not
    3395             :  be altered or deleted by the caller.
    3396             : 
    3397             :  This function is the same as the C++ method OGRLayer::GetSpatialFilter().
    3398             : 
    3399             :  @param hLayer handle to the layer to get the spatial filter from.
    3400             :  @return a handle to the spatial filter geometry.
    3401             :  */
    3402             : 
    3403           5 : OGRGeometryH OGR_L_GetSpatialFilter(OGRLayerH hLayer)
    3404             : 
    3405             : {
    3406           5 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialFilter", nullptr);
    3407             : 
    3408             : #ifdef OGRAPISPY_ENABLED
    3409           5 :     if (bOGRAPISpyEnabled)
    3410           2 :         OGRAPISpy_L_GetSpatialFilter(hLayer);
    3411             : #endif
    3412             : 
    3413           5 :     return OGRGeometry::ToHandle(
    3414          10 :         OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
    3415             : }
    3416             : 
    3417             : /************************************************************************/
    3418             : /*           ValidateGeometryFieldIndexForSetSpatialFilter()            */
    3419             : /************************************************************************/
    3420             : 
    3421             : //! @cond Doxygen_Suppress
    3422       53971 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
    3423             :     int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
    3424             : {
    3425       53971 :     if (iGeomField == 0 && poGeomIn == nullptr &&
    3426           0 :         GetLayerDefn()->GetGeomFieldCount() == 0)
    3427             :     {
    3428             :         // Setting a null spatial filter on geometry field idx 0
    3429             :         // when there are no geometry field can't harm, and is accepted silently
    3430             :         // for backward compatibility with existing practice.
    3431             :     }
    3432      107657 :     else if (iGeomField < 0 ||
    3433       53686 :              iGeomField >= GetLayerDefn()->GetGeomFieldCount())
    3434             :     {
    3435         663 :         if (iGeomField == 0)
    3436             :         {
    3437          91 :             CPLError(
    3438             :                 CE_Failure, CPLE_AppDefined,
    3439             :                 bIsSelectLayer
    3440             :                     ? "Cannot set spatial filter: no geometry field selected."
    3441             :                     : "Cannot set spatial filter: no geometry field present in "
    3442             :                       "layer.");
    3443             :         }
    3444             :         else
    3445             :         {
    3446         572 :             CPLError(CE_Failure, CPLE_AppDefined,
    3447             :                      "Cannot set spatial filter on non-existing geometry field "
    3448             :                      "of index %d.",
    3449             :                      iGeomField);
    3450             :         }
    3451         663 :         return false;
    3452             :     }
    3453       53308 :     return true;
    3454             : }
    3455             : 
    3456             : //! @endcond
    3457             : 
    3458             : /************************************************************************/
    3459             : /*                          SetSpatialFilter()                          */
    3460             : /************************************************************************/
    3461             : 
    3462             : /**
    3463             :  \brief Set a new spatial filter.
    3464             : 
    3465             :  This method set the geometry to be used as a spatial filter when
    3466             :  fetching features via the GetNextFeature() method.  Only features that
    3467             :  geometrically intersect the filter geometry will be returned.
    3468             : 
    3469             :  Currently this test is may be inaccurately implemented, but it is
    3470             :  guaranteed that all features whose envelope (as returned by
    3471             :  OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
    3472             :  will be returned.  This can result in more shapes being returned that
    3473             :  should strictly be the case.
    3474             : 
    3475             :  Features with null or empty geometries will never
    3476             :  be considered as matching a spatial filter.
    3477             : 
    3478             :  This method makes an internal copy of the passed geometry.  The
    3479             :  passed geometry remains the responsibility of the caller, and may
    3480             :  be safely destroyed.
    3481             : 
    3482             :  For the time being the passed filter geometry should be in the same
    3483             :  SRS as the layer (as returned by OGRLayer::GetSpatialRef()).  In the
    3484             :  future this may be generalized.
    3485             : 
    3486             :  This method is the same as the C function OGR_L_SetSpatialFilter().
    3487             : 
    3488             :  @param poFilter the geometry to use as a filtering region.  NULL may
    3489             :  be passed indicating that the current spatial filter should be cleared,
    3490             :  but no new one instituted.
    3491             :  */
    3492             : 
    3493        6947 : OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
    3494             : 
    3495             : {
    3496        6947 :     return SetSpatialFilter(0, poFilter);
    3497             : }
    3498             : 
    3499             : /**
    3500             :  \brief Set a new spatial filter.
    3501             : 
    3502             :  This method set the geometry to be used as a spatial filter when
    3503             :  fetching features via the GetNextFeature() method.  Only features that
    3504             :  geometrically intersect the filter geometry will be returned.
    3505             : 
    3506             :  Currently this test is may be inaccurately implemented, but it is
    3507             :  guaranteed that all features who's envelope (as returned by
    3508             :  OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
    3509             :  will be returned.  This can result in more shapes being returned that
    3510             :  should strictly be the case.
    3511             : 
    3512             :  This method makes an internal copy of the passed geometry.  The
    3513             :  passed geometry remains the responsibility of the caller, and may
    3514             :  be safely destroyed.
    3515             : 
    3516             :  For the time being the passed filter geometry should be in the same
    3517             :  SRS as the geometry field definition it corresponds to (as returned by
    3518             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
    3519             :  future this may be generalized.
    3520             : 
    3521             :  Note that only the last spatial filter set is applied, even if several
    3522             :  successive calls are done with different iGeomField values.
    3523             : 
    3524             :  This method is the same as the C function OGR_L_SetSpatialFilterEx().
    3525             : 
    3526             :  @param iGeomField index of the geometry field on which the spatial filter
    3527             :  operates.
    3528             :  @param poFilter the geometry to use as a filtering region.  NULL may
    3529             :  be passed indicating that the current spatial filter should be cleared,
    3530             :  but no new one instituted.
    3531             :  */
    3532             : 
    3533       66506 : OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
    3534             : 
    3535             : {
    3536       66506 :     if (iGeomField == 0)
    3537             :     {
    3538      117875 :         if (poFilter &&
    3539       52669 :             !ValidateGeometryFieldIndexForSetSpatialFilter(0, poFilter))
    3540             :         {
    3541          91 :             return OGRERR_FAILURE;
    3542             :         }
    3543             :     }
    3544             :     else
    3545             :     {
    3546        1300 :         if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
    3547             :                                                            poFilter))
    3548             :         {
    3549         572 :             return OGRERR_FAILURE;
    3550             :         }
    3551             :     }
    3552             : 
    3553       65843 :     return ISetSpatialFilter(iGeomField, poFilter);
    3554             : }
    3555             : 
    3556             : /************************************************************************/
    3557             : /*                         ISetSpatialFilter()                          */
    3558             : /************************************************************************/
    3559             : 
    3560             : /**
    3561             :  \brief Set a new spatial filter.
    3562             : 
    3563             :  Virtual method implemented by drivers since 3.11. In previous versions,
    3564             :  SetSpatialFilter() / SetSpatialFilterRect() itself was the virtual method.
    3565             : 
    3566             :  Driver implementations, when wanting to call the base method, must take
    3567             :  care of calling OGRLayer::ISetSpatialFilter() (and note the public method without
    3568             :  the leading I).
    3569             : 
    3570             :  @param iGeomField index of the geometry field on which the spatial filter
    3571             :  operates.
    3572             :  @param poFilter the geometry to use as a filtering region.  NULL may
    3573             :  be passed indicating that the current spatial filter should be cleared,
    3574             :  but no new one instituted.
    3575             : 
    3576             :  @since GDAL 3.11
    3577             :  */
    3578             : 
    3579       37821 : OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
    3580             : 
    3581             : {
    3582       37821 :     m_iGeomFieldFilter = iGeomField;
    3583       37821 :     if (InstallFilter(poFilter))
    3584       29311 :         ResetReading();
    3585       37821 :     return OGRERR_NONE;
    3586             : }
    3587             : 
    3588             : /************************************************************************/
    3589             : /*                       OGR_L_SetSpatialFilter()                       */
    3590             : /************************************************************************/
    3591             : 
    3592             : /**
    3593             :  \brief Set a new spatial filter.
    3594             : 
    3595             :  This function set the geometry to be used as a spatial filter when
    3596             :  fetching features via the OGR_L_GetNextFeature() function.  Only
    3597             :  features that geometrically intersect the filter geometry will be
    3598             :  returned.
    3599             : 
    3600             :  Currently this test is may be inaccurately implemented, but it is
    3601             :  guaranteed that all features whose envelope (as returned by
    3602             :  OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
    3603             :  will be returned.  This can result in more shapes being returned that
    3604             :  should strictly be the case.
    3605             : 
    3606             :  Features with null or empty geometries will never
    3607             :  be considered as matching a spatial filter.
    3608             : 
    3609             :  This function makes an internal copy of the passed geometry.  The
    3610             :  passed geometry remains the responsibility of the caller, and may
    3611             :  be safely destroyed.
    3612             : 
    3613             :  For the time being the passed filter geometry should be in the same
    3614             :  SRS as the layer (as returned by OGR_L_GetSpatialRef()).  In the
    3615             :  future this may be generalized.
    3616             : 
    3617             :  This function is the same as the C++ method OGRLayer::SetSpatialFilter.
    3618             : 
    3619             :  @param hLayer handle to the layer on which to set the spatial filter.
    3620             :  @param hGeom handle to the geometry to use as a filtering region.  NULL may
    3621             :  be passed indicating that the current spatial filter should be cleared,
    3622             :  but no new one instituted.
    3623             : 
    3624             :  */
    3625             : 
    3626         784 : void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
    3627             : 
    3628             : {
    3629         784 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
    3630             : 
    3631             : #ifdef OGRAPISPY_ENABLED
    3632         784 :     if (bOGRAPISpyEnabled)
    3633           4 :         OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
    3634             : #endif
    3635             : 
    3636        1568 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
    3637         784 :         OGRGeometry::FromHandle(hGeom));
    3638             : }
    3639             : 
    3640             : /************************************************************************/
    3641             : /*                      OGR_L_SetSpatialFilterEx()                      */
    3642             : /************************************************************************/
    3643             : 
    3644             : /**
    3645             :  \brief Set a new spatial filter.
    3646             : 
    3647             :  This function set the geometry to be used as a spatial filter when
    3648             :  fetching features via the OGR_L_GetNextFeature() function.  Only
    3649             :  features that geometrically intersect the filter geometry will be
    3650             :  returned.
    3651             : 
    3652             :  Currently this test is may be inaccurately implemented, but it is
    3653             :  guaranteed that all features who's envelope (as returned by
    3654             :  OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
    3655             :  will be returned.  This can result in more shapes being returned that
    3656             :  should strictly be the case.
    3657             : 
    3658             :  This function makes an internal copy of the passed geometry.  The
    3659             :  passed geometry remains the responsibility of the caller, and may
    3660             :  be safely destroyed.
    3661             : 
    3662             :  For the time being the passed filter geometry should be in the same
    3663             :  SRS as the geometry field definition it corresponds to (as returned by
    3664             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
    3665             :  future this may be generalized.
    3666             : 
    3667             :  Note that only the last spatial filter set is applied, even if several
    3668             :  successive calls are done with different iGeomField values.
    3669             : 
    3670             :  This function is the same as the C++ method OGRLayer::SetSpatialFilter.
    3671             : 
    3672             :  @param hLayer handle to the layer on which to set the spatial filter.
    3673             :  @param iGeomField index of the geometry field on which the spatial filter
    3674             :  operates.
    3675             :  @param hGeom handle to the geometry to use as a filtering region.  NULL may
    3676             :  be passed indicating that the current spatial filter should be cleared,
    3677             :  but no new one instituted.
    3678             : 
    3679             :  */
    3680             : 
    3681          12 : void OGR_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
    3682             :                               OGRGeometryH hGeom)
    3683             : 
    3684             : {
    3685          12 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterEx");
    3686             : 
    3687             : #ifdef OGRAPISPY_ENABLED
    3688          12 :     if (bOGRAPISpyEnabled)
    3689           2 :         OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
    3690             : #endif
    3691             : 
    3692          24 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
    3693          12 :         iGeomField, OGRGeometry::FromHandle(hGeom));
    3694             : }
    3695             : 
    3696             : /************************************************************************/
    3697             : /*                        SetSpatialFilterRect()                        */
    3698             : /************************************************************************/
    3699             : 
    3700             : /**
    3701             :  \brief Set a new rectangular spatial filter.
    3702             : 
    3703             :  This method set rectangle to be used as a spatial filter when
    3704             :  fetching features via the GetNextFeature() method.  Only features that
    3705             :  geometrically intersect the given rectangle will be returned.
    3706             : 
    3707             :  The x/y values should be in the same coordinate system as the layer as
    3708             :  a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
    3709             :  method is normally implemented as creating a 5 vertex closed rectangular
    3710             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    3711             :  a convenience.
    3712             : 
    3713             :  The only way to clear a spatial filter set with this method is to
    3714             :  call OGRLayer::SetSpatialFilter(NULL).
    3715             : 
    3716             :  This method is the same as the C function OGR_L_SetSpatialFilterRect().
    3717             : 
    3718             :  @param dfMinX the minimum X coordinate for the rectangular region.
    3719             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    3720             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    3721             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    3722             : 
    3723             :  */
    3724             : 
    3725       48335 : OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
    3726             :                                       double dfMaxX, double dfMaxY)
    3727             : 
    3728             : {
    3729       48335 :     return SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
    3730             : }
    3731             : 
    3732             : /**
    3733             :  \brief Set a new rectangular spatial filter.
    3734             : 
    3735             :  This method set rectangle to be used as a spatial filter when
    3736             :  fetching features via the GetNextFeature() method.  Only features that
    3737             :  geometrically intersect the given rectangle will be returned.
    3738             : 
    3739             :  The x/y values should be in the same coordinate system as as the geometry
    3740             :  field definition it corresponds to (as returned by
    3741             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
    3742             :  method is normally implemented as creating a 5 vertex closed rectangular
    3743             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    3744             :  a convenience.
    3745             : 
    3746             :  The only way to clear a spatial filter set with this method is to
    3747             :  call OGRLayer::SetSpatialFilter(NULL).
    3748             : 
    3749             :  This method is the same as the C function OGR_L_SetSpatialFilterRectEx().
    3750             : 
    3751             :  @param iGeomField index of the geometry field on which the spatial filter
    3752             :  operates.
    3753             :  @param dfMinX the minimum X coordinate for the rectangular region.
    3754             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    3755             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    3756             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    3757             :  */
    3758             : 
    3759       48375 : OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
    3760             :                                       double dfMinY, double dfMaxX,
    3761             :                                       double dfMaxY)
    3762             : 
    3763             : {
    3764       96750 :     auto poRing = std::make_unique<OGRLinearRing>();
    3765       96750 :     OGRPolygon oPoly;
    3766             : 
    3767       48375 :     poRing->addPoint(dfMinX, dfMinY);
    3768       48375 :     poRing->addPoint(dfMinX, dfMaxY);
    3769       48375 :     poRing->addPoint(dfMaxX, dfMaxY);
    3770       48375 :     poRing->addPoint(dfMaxX, dfMinY);
    3771       48375 :     poRing->addPoint(dfMinX, dfMinY);
    3772             : 
    3773       48375 :     oPoly.addRing(std::move(poRing));
    3774             : 
    3775       96750 :     return SetSpatialFilter(iGeomField, &oPoly);
    3776             : }
    3777             : 
    3778             : /************************************************************************/
    3779             : /*                     OGR_L_SetSpatialFilterRect()                     */
    3780             : /************************************************************************/
    3781             : 
    3782             : /**
    3783             :  \brief Set a new rectangular spatial filter.
    3784             : 
    3785             :  This method set rectangle to be used as a spatial filter when
    3786             :  fetching features via the OGR_L_GetNextFeature() method.  Only features that
    3787             :  geometrically intersect the given rectangle will be returned.
    3788             : 
    3789             :  The x/y values should be in the same coordinate system as the layer as
    3790             :  a whole (as returned by OGRLayer::GetSpatialRef()).   Internally this
    3791             :  method is normally implemented as creating a 5 vertex closed rectangular
    3792             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    3793             :  a convenience.
    3794             : 
    3795             :  The only way to clear a spatial filter set with this method is to
    3796             :  call OGRLayer::SetSpatialFilter(NULL).
    3797             : 
    3798             :  This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
    3799             : 
    3800             :  @param hLayer handle to the layer on which to set the spatial filter.
    3801             :  @param dfMinX the minimum X coordinate for the rectangular region.
    3802             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    3803             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    3804             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    3805             : 
    3806             :  */
    3807             : 
    3808       48011 : void OGR_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX, double dfMinY,
    3809             :                                 double dfMaxX, double dfMaxY)
    3810             : 
    3811             : {
    3812       48011 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRect");
    3813             : 
    3814             : #ifdef OGRAPISPY_ENABLED
    3815       48011 :     if (bOGRAPISpyEnabled)
    3816           2 :         OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX,
    3817             :                                          dfMaxY);
    3818             : #endif
    3819             : 
    3820       48011 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX,
    3821             :                                                        dfMaxY);
    3822             : }
    3823             : 
    3824             : /************************************************************************/
    3825             : /*                    OGR_L_SetSpatialFilterRectEx()                    */
    3826             : /************************************************************************/
    3827             : 
    3828             : /**
    3829             :  \brief Set a new rectangular spatial filter.
    3830             : 
    3831             :  This method set rectangle to be used as a spatial filter when
    3832             :  fetching features via the OGR_L_GetNextFeature() method.  Only features that
    3833             :  geometrically intersect the given rectangle will be returned.
    3834             : 
    3835             :  The x/y values should be in the same coordinate system as as the geometry
    3836             :  field definition it corresponds to (as returned by
    3837             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
    3838             :  method is normally implemented as creating a 5 vertex closed rectangular
    3839             :  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
    3840             :  a convenience.
    3841             : 
    3842             :  The only way to clear a spatial filter set with this method is to
    3843             :  call OGRLayer::SetSpatialFilter(NULL).
    3844             : 
    3845             :  This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
    3846             : 
    3847             :  @param hLayer handle to the layer on which to set the spatial filter.
    3848             :  @param iGeomField index of the geometry field on which the spatial filter
    3849             :  operates.
    3850             :  @param dfMinX the minimum X coordinate for the rectangular region.
    3851             :  @param dfMinY the minimum Y coordinate for the rectangular region.
    3852             :  @param dfMaxX the maximum X coordinate for the rectangular region.
    3853             :  @param dfMaxY the maximum Y coordinate for the rectangular region.
    3854             : */
    3855             : 
    3856          15 : void OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
    3857             :                                   double dfMinX, double dfMinY, double dfMaxX,
    3858             :                                   double dfMaxY)
    3859             : 
    3860             : {
    3861          15 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRectEx");
    3862             : 
    3863             : #ifdef OGRAPISPY_ENABLED
    3864          15 :     if (bOGRAPISpyEnabled)
    3865           2 :         OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY,
    3866             :                                            dfMaxX, dfMaxY);
    3867             : #endif
    3868             : 
    3869          15 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(iGeomField, dfMinX,
    3870             :                                                        dfMinY, dfMaxX, dfMaxY);
    3871             : }
    3872             : 
    3873             : /************************************************************************/
    3874             : /*                           InstallFilter()                            */
    3875             : /*                                                                      */
    3876             : /*      This method is only intended to be used from within             */
    3877             : /*      drivers, normally from the SetSpatialFilter() method.           */
    3878             : /*      It installs a filter, and also tests it to see if it is         */
    3879             : /*      rectangular.  If so, it this is kept track of alongside the     */
    3880             : /*      filter geometry itself so we can do cheaper comparisons in      */
    3881             : /*      the FilterGeometry() call.                                      */
    3882             : /*                                                                      */
    3883             : /*      Returns TRUE if the newly installed filter differs in some      */
    3884             : /*      way from the current one.                                       */
    3885             : /************************************************************************/
    3886             : 
    3887             : //! @cond Doxygen_Suppress
    3888       64803 : int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
    3889             : 
    3890             : {
    3891       64803 :     if (m_poFilterGeom == poFilter)
    3892        9936 :         return FALSE;
    3893             : 
    3894             :     /* -------------------------------------------------------------------- */
    3895             :     /*      Replace the existing filter.                                    */
    3896             :     /* -------------------------------------------------------------------- */
    3897       54867 :     if (m_poFilterGeom != nullptr)
    3898             :     {
    3899       51603 :         delete m_poFilterGeom;
    3900       51603 :         m_poFilterGeom = nullptr;
    3901             :     }
    3902             : 
    3903       54867 :     if (m_pPreparedFilterGeom != nullptr)
    3904             :     {
    3905       51603 :         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
    3906       51603 :         m_pPreparedFilterGeom = nullptr;
    3907             :     }
    3908             : 
    3909       54867 :     if (poFilter != nullptr)
    3910       52682 :         m_poFilterGeom = poFilter->clone();
    3911             : 
    3912       54867 :     m_bFilterIsEnvelope = FALSE;
    3913             : 
    3914       54867 :     if (m_poFilterGeom == nullptr)
    3915        2185 :         return TRUE;
    3916             : 
    3917       52682 :     m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
    3918             : 
    3919             :     /* Compile geometry filter as a prepared geometry */
    3920       52682 :     m_pPreparedFilterGeom =
    3921       52682 :         OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
    3922             : 
    3923       52682 :     m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
    3924             : 
    3925       52682 :     return TRUE;
    3926             : }
    3927             : 
    3928             : //! @endcond
    3929             : 
    3930             : /************************************************************************/
    3931             : /*                  DoesGeometryHavePointInEnvelope()                   */
    3932             : /************************************************************************/
    3933             : 
    3934        5989 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
    3935             :                                             const OGREnvelope &sEnvelope)
    3936             : {
    3937        5989 :     const OGRLineString *poLS = nullptr;
    3938             : 
    3939        5989 :     switch (wkbFlatten(poGeometry->getGeometryType()))
    3940             :     {
    3941          36 :         case wkbPoint:
    3942             :         {
    3943          36 :             const auto poPoint = poGeometry->toPoint();
    3944          36 :             const double x = poPoint->getX();
    3945          36 :             const double y = poPoint->getY();
    3946          31 :             return (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
    3947          67 :                     x <= sEnvelope.MaxX && y <= sEnvelope.MaxY);
    3948             :         }
    3949             : 
    3950         435 :         case wkbLineString:
    3951         435 :             poLS = poGeometry->toLineString();
    3952         435 :             break;
    3953             : 
    3954        4738 :         case wkbPolygon:
    3955             :         {
    3956        4738 :             const OGRPolygon *poPoly = poGeometry->toPolygon();
    3957        4738 :             poLS = poPoly->getExteriorRing();
    3958        4738 :             break;
    3959             :         }
    3960             : 
    3961         539 :         case wkbMultiPoint:
    3962             :         case wkbMultiLineString:
    3963             :         case wkbMultiPolygon:
    3964             :         case wkbGeometryCollection:
    3965             :         {
    3966         771 :             for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
    3967             :             {
    3968         685 :                 if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
    3969         453 :                     return true;
    3970             :             }
    3971          86 :             return false;
    3972             :         }
    3973             : 
    3974         241 :         default:
    3975         241 :             return false;
    3976             :     }
    3977             : 
    3978        5173 :     if (poLS != nullptr)
    3979             :     {
    3980        5173 :         const int nNumPoints = poLS->getNumPoints();
    3981       59770 :         for (int i = 0; i < nNumPoints; i++)
    3982             :         {
    3983       58646 :             const double x = poLS->getX(i);
    3984       58646 :             const double y = poLS->getY(i);
    3985       58646 :             if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
    3986       24295 :                 x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
    3987             :             {
    3988        4049 :                 return true;
    3989             :             }
    3990             :         }
    3991             :     }
    3992             : 
    3993        1124 :     return false;
    3994             : }
    3995             : 
    3996             : /************************************************************************/
    3997             : /*                           FilterGeometry()                           */
    3998             : /*                                                                      */
    3999             : /*      Compare the passed in geometry to the currently installed       */
    4000             : /*      filter.  Optimize for case where filter is just an              */
    4001             : /*      envelope.                                                       */
    4002             : /************************************************************************/
    4003             : 
    4004             : //! @cond Doxygen_Suppress
    4005      444832 : int OGRLayer::FilterGeometry(const OGRGeometry *poGeometry)
    4006             : 
    4007             : {
    4008             :     /* -------------------------------------------------------------------- */
    4009             :     /*      In trivial cases of new filter or target geometry, we accept    */
    4010             :     /*      an intersection.  No geometry is taken to mean "the whole       */
    4011             :     /*      world".                                                         */
    4012             :     /* -------------------------------------------------------------------- */
    4013      444832 :     if (m_poFilterGeom == nullptr)
    4014         376 :         return TRUE;
    4015             : 
    4016      444456 :     if (poGeometry == nullptr || poGeometry->IsEmpty())
    4017         303 :         return FALSE;
    4018             : 
    4019             :     /* -------------------------------------------------------------------- */
    4020             :     /*      Compute the target geometry envelope, and if there is no        */
    4021             :     /*      intersection between the envelopes we are sure not to have      */
    4022             :     /*      any intersection.                                               */
    4023             :     /* -------------------------------------------------------------------- */
    4024      444153 :     OGREnvelope sGeomEnv;
    4025             : 
    4026      444153 :     poGeometry->getEnvelope(&sGeomEnv);
    4027             : 
    4028      444153 :     if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
    4029      296426 :         sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
    4030      231401 :         m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
    4031      133884 :         m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
    4032      326306 :         return FALSE;
    4033             : 
    4034             :     /* -------------------------------------------------------------------- */
    4035             :     /*      If the filter geometry is its own envelope and if the           */
    4036             :     /*      envelope of the geometry is inside the filter geometry,         */
    4037             :     /*      the geometry itself is inside the filter geometry               */
    4038             :     /* -------------------------------------------------------------------- */
    4039      117847 :     if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
    4040      112088 :         sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
    4041      110660 :         sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
    4042      109743 :         sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
    4043             :     {
    4044      109367 :         return TRUE;
    4045             :     }
    4046             :     else
    4047             :     {
    4048             :         // If the filter geometry is its own envelope and if the geometry has
    4049             :         // at least one point inside the filter geometry, the geometry itself
    4050             :         // intersects the filter geometry.
    4051        8480 :         if (m_bFilterIsEnvelope)
    4052             :         {
    4053        5304 :             if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
    4054        4059 :                 return true;
    4055             :         }
    4056             : 
    4057             :         /* --------------------------------------------------------------------
    4058             :          */
    4059             :         /*      Fallback to full intersect test (using GEOS) if we still */
    4060             :         /*      don't know for sure. */
    4061             :         /* --------------------------------------------------------------------
    4062             :          */
    4063        4421 :         if (OGRGeometryFactory::haveGEOS())
    4064             :         {
    4065             :             // CPLDebug("OGRLayer", "GEOS intersection");
    4066        4421 :             if (m_pPreparedFilterGeom != nullptr)
    4067        4421 :                 return OGRPreparedGeometryIntersects(
    4068             :                     m_pPreparedFilterGeom,
    4069             :                     OGRGeometry::ToHandle(
    4070        4421 :                         const_cast<OGRGeometry *>(poGeometry)));
    4071             :             else
    4072           0 :                 return m_poFilterGeom->Intersects(poGeometry);
    4073             :         }
    4074             :         else
    4075           0 :             return TRUE;
    4076             :     }
    4077             : }
    4078             : 
    4079             : /************************************************************************/
    4080             : /*                         FilterWKBGeometry()                          */
    4081             : /************************************************************************/
    4082             : 
    4083         230 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
    4084             :                                  bool bEnvelopeAlreadySet,
    4085             :                                  OGREnvelope &sEnvelope) const
    4086             : {
    4087         230 :     OGRPreparedGeometry *pPreparedFilterGeom = m_pPreparedFilterGeom;
    4088             :     bool bRet =
    4089         460 :         FilterWKBGeometry(pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope,
    4090         230 :                           m_poFilterGeom, CPL_TO_BOOL(m_bFilterIsEnvelope),
    4091         230 :                           m_sFilterEnvelope, pPreparedFilterGeom);
    4092         230 :     const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
    4093         230 :     return bRet;
    4094             : }
    4095             : 
    4096             : /* static */
    4097         334 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
    4098             :                                  bool bEnvelopeAlreadySet,
    4099             :                                  OGREnvelope &sEnvelope,
    4100             :                                  const OGRGeometry *poFilterGeom,
    4101             :                                  bool bFilterIsEnvelope,
    4102             :                                  const OGREnvelope &sFilterEnvelope,
    4103             :                                  OGRPreparedGeometry *&pPreparedFilterGeom)
    4104             : {
    4105         334 :     if (!poFilterGeom)
    4106           0 :         return true;
    4107             : 
    4108         637 :     if ((bEnvelopeAlreadySet ||
    4109         668 :          OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
    4110         334 :         sFilterEnvelope.Intersects(sEnvelope))
    4111             :     {
    4112         161 :         if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
    4113             :         {
    4114          98 :             return true;
    4115             :         }
    4116             :         else
    4117             :         {
    4118         126 :             if (bFilterIsEnvelope &&
    4119          63 :                 OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
    4120             :             {
    4121          51 :                 return true;
    4122             :             }
    4123          12 :             else if (OGRGeometryFactory::haveGEOS())
    4124             :             {
    4125          12 :                 OGRGeometry *poGeom = nullptr;
    4126          12 :                 int ret = FALSE;
    4127          12 :                 if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
    4128          12 :                                                       nWKBSize) == OGRERR_NONE)
    4129             :                 {
    4130          12 :                     if (!pPreparedFilterGeom)
    4131             :                     {
    4132           0 :                         pPreparedFilterGeom =
    4133           0 :                             OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
    4134             :                                 const_cast<OGRGeometry *>(poFilterGeom)));
    4135             :                     }
    4136          12 :                     if (pPreparedFilterGeom)
    4137          12 :                         ret = OGRPreparedGeometryIntersects(
    4138             :                             pPreparedFilterGeom,
    4139             :                             OGRGeometry::ToHandle(
    4140             :                                 const_cast<OGRGeometry *>(poGeom)));
    4141             :                     else
    4142           0 :                         ret = poFilterGeom->Intersects(poGeom);
    4143             :                 }
    4144          12 :                 delete poGeom;
    4145          12 :                 return CPL_TO_BOOL(ret);
    4146             :             }
    4147             :             else
    4148             :             {
    4149             :                 // Assume intersection
    4150           0 :                 return true;
    4151             :             }
    4152             :         }
    4153             :     }
    4154             : 
    4155         173 :     return false;
    4156             : }
    4157             : 
    4158             : /************************************************************************/
    4159             : /*                      PrepareStartTransaction()                       */
    4160             : /************************************************************************/
    4161             : 
    4162        3060 : void OGRLayer::PrepareStartTransaction()
    4163             : {
    4164        3060 :     m_apoFieldDefnChanges.clear();
    4165        3060 :     m_apoGeomFieldDefnChanges.clear();
    4166        3060 : }
    4167             : 
    4168             : /************************************************************************/
    4169             : /*                     FinishRollbackTransaction()                      */
    4170             : /************************************************************************/
    4171             : 
    4172         173 : void OGRLayer::FinishRollbackTransaction(const std::string &osSavepointName)
    4173             : {
    4174             : 
    4175             :     // Deleted fields can be safely removed from the storage after being restored.
    4176         346 :     std::vector<int> toBeRemoved;
    4177             : 
    4178         173 :     bool bSavepointFound = false;
    4179             : 
    4180             :     // Loop through all changed fields and reset them to their previous state.
    4181         376 :     for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
    4182             :          i--)
    4183             :     {
    4184         203 :         auto &oFieldChange = m_apoFieldDefnChanges[i];
    4185             : 
    4186         203 :         if (!osSavepointName.empty())
    4187             :         {
    4188         172 :             if (oFieldChange.osSavepointName == osSavepointName)
    4189             :             {
    4190          60 :                 bSavepointFound = true;
    4191             :             }
    4192         112 :             else if (bSavepointFound)
    4193             :             {
    4194          56 :                 continue;
    4195             :             }
    4196             :         }
    4197             : 
    4198         147 :         CPLAssert(oFieldChange.poFieldDefn);
    4199         147 :         const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
    4200         147 :         const int iField = oFieldChange.iField;
    4201         147 :         if (iField >= 0)
    4202             :         {
    4203         147 :             switch (oFieldChange.eChangeType)
    4204             :             {
    4205         128 :                 case FieldChangeType::DELETE_FIELD:
    4206             :                 {
    4207             :                     // Transfer ownership of the field to the layer
    4208         256 :                     whileUnsealing(GetLayerDefn())
    4209         128 :                         ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
    4210             : 
    4211             :                     // Now move the field to the right place
    4212             :                     // from the last position to its original position
    4213         128 :                     const int iFieldCount = GetLayerDefn()->GetFieldCount();
    4214         128 :                     CPLAssert(iFieldCount > 0);
    4215         128 :                     CPLAssert(iFieldCount > iField);
    4216         256 :                     std::vector<int> anOrder(iFieldCount);
    4217         204 :                     for (int j = 0; j < iField; j++)
    4218             :                     {
    4219          76 :                         anOrder[j] = j;
    4220             :                     }
    4221         248 :                     for (int j = iField + 1; j < iFieldCount; j++)
    4222             :                     {
    4223         120 :                         anOrder[j] = j - 1;
    4224             :                     }
    4225         128 :                     anOrder[iField] = iFieldCount - 1;
    4226         256 :                     if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
    4227         128 :                                            ->ReorderFieldDefns(anOrder.data()))
    4228             :                     {
    4229         128 :                         toBeRemoved.push_back(i);
    4230             :                     }
    4231             :                     else
    4232             :                     {
    4233           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    4234             :                                  "Failed to restore deleted field %s", pszName);
    4235             :                     }
    4236         128 :                     break;
    4237             :                 }
    4238           8 :                 case FieldChangeType::ALTER_FIELD:
    4239             :                 {
    4240             :                     OGRFieldDefn *poFieldDefn =
    4241           8 :                         GetLayerDefn()->GetFieldDefn(iField);
    4242           8 :                     if (poFieldDefn)
    4243             :                     {
    4244           8 :                         *poFieldDefn = *oFieldChange.poFieldDefn;
    4245           8 :                         toBeRemoved.push_back(i);
    4246             :                     }
    4247             :                     else
    4248             :                     {
    4249           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    4250             :                                  "Failed to restore altered field %s", pszName);
    4251             :                     }
    4252           8 :                     break;
    4253             :                 }
    4254          11 :                 case FieldChangeType::ADD_FIELD:
    4255             :                 {
    4256             :                     std::unique_ptr<OGRFieldDefn> poFieldDef =
    4257          22 :                         GetLayerDefn()->StealFieldDefn(iField);
    4258          11 :                     if (poFieldDef)
    4259             :                     {
    4260          11 :                         oFieldChange.poFieldDefn = std::move(poFieldDef);
    4261             :                     }
    4262             :                     else
    4263             :                     {
    4264           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    4265             :                                  "Failed to delete added field %s", pszName);
    4266             :                     }
    4267          11 :                     break;
    4268             :                 }
    4269             :             }
    4270             :         }
    4271             :         else
    4272             :         {
    4273           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    4274             :                      "Failed to restore field %s (field not found at index %d)",
    4275             :                      pszName, iField);
    4276             :         }
    4277             :     }
    4278             : 
    4279             :     // Remove from the storage the deleted fields that have been restored
    4280         309 :     for (const auto &i : toBeRemoved)
    4281             :     {
    4282         136 :         m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
    4283             :     }
    4284             : 
    4285             :     /**********************************************************************/
    4286             :     /* Reset geometry fields to their previous state.                    */
    4287             :     /**********************************************************************/
    4288             : 
    4289         173 :     bSavepointFound = false;
    4290             : 
    4291             :     // Loop through all changed geometry fields and reset them to their previous state.
    4292         173 :     for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
    4293             :          i--)
    4294             :     {
    4295           0 :         auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
    4296             : 
    4297           0 :         if (!osSavepointName.empty())
    4298             :         {
    4299           0 :             if (oGeomFieldChange.osSavepointName == osSavepointName)
    4300             :             {
    4301           0 :                 bSavepointFound = true;
    4302             :             }
    4303           0 :             else if (bSavepointFound)
    4304             :             {
    4305           0 :                 continue;
    4306             :             }
    4307             :         }
    4308           0 :         const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
    4309           0 :         const int iGeomField = oGeomFieldChange.iField;
    4310           0 :         if (iGeomField >= 0)
    4311             :         {
    4312           0 :             switch (oGeomFieldChange.eChangeType)
    4313             :             {
    4314           0 :                 case FieldChangeType::DELETE_FIELD:
    4315             :                 case FieldChangeType::ALTER_FIELD:
    4316             :                 {
    4317             :                     // Currently not handled by OGR for geometry fields
    4318           0 :                     break;
    4319             :                 }
    4320           0 :                 case FieldChangeType::ADD_FIELD:
    4321             :                 {
    4322             :                     std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
    4323           0 :                         GetLayerDefn()->StealGeomFieldDefn(
    4324           0 :                             oGeomFieldChange.iField);
    4325           0 :                     if (poGeomFieldDef)
    4326             :                     {
    4327             :                         oGeomFieldChange.poFieldDefn =
    4328           0 :                             std::move(poGeomFieldDef);
    4329             :                     }
    4330             :                     else
    4331             :                     {
    4332           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    4333             :                                  "Failed to delete added geometry field %s",
    4334             :                                  pszName);
    4335             :                     }
    4336           0 :                     break;
    4337             :                 }
    4338             :             }
    4339             :         }
    4340             :         else
    4341             :         {
    4342           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    4343             :                      "Failed to restore geometry field %s (field not found at "
    4344             :                      "index %d)",
    4345             :                      pszName, oGeomFieldChange.iField);
    4346             :         }
    4347             :     }
    4348         173 : }
    4349             : 
    4350             : //! @endcond
    4351             : 
    4352             : /************************************************************************/
    4353             : /*                       OGRLayer::ResetReading()                       */
    4354             : /************************************************************************/
    4355             : 
    4356             : /**
    4357             :  \fn void OGRLayer::ResetReading();
    4358             : 
    4359             :  \brief Reset feature reading to start on the first feature.
    4360             : 
    4361             :  This affects GetNextFeature() and GetArrowStream().
    4362             : 
    4363             :  This method is the same as the C function OGR_L_ResetReading().
    4364             : */
    4365             : 
    4366             : /************************************************************************/
    4367             : /*                         OGR_L_ResetReading()                         */
    4368             : /************************************************************************/
    4369             : 
    4370             : /**
    4371             :  \brief Reset feature reading to start on the first feature.
    4372             : 
    4373             :  This affects GetNextFeature() and GetArrowStream().
    4374             : 
    4375             :  This function is the same as the C++ method OGRLayer::ResetReading().
    4376             : 
    4377             :  @param hLayer handle to the layer on which features are read.
    4378             : */
    4379             : 
    4380       18743 : void OGR_L_ResetReading(OGRLayerH hLayer)
    4381             : 
    4382             : {
    4383       18743 :     VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
    4384             : 
    4385             : #ifdef OGRAPISPY_ENABLED
    4386       18743 :     if (bOGRAPISpyEnabled)
    4387           2 :         OGRAPISpy_L_ResetReading(hLayer);
    4388             : #endif
    4389             : 
    4390       18743 :     OGRLayer::FromHandle(hLayer)->ResetReading();
    4391             : }
    4392             : 
    4393             : /************************************************************************/
    4394             : /*                       InitializeIndexSupport()                       */
    4395             : /*                                                                      */
    4396             : /*      This is only intended to be called by driver layer              */
    4397             : /*      implementations but we don't make it protected so that the      */
    4398             : /*      datasources can do it too if that is more appropriate.          */
    4399             : /************************************************************************/
    4400             : 
    4401             : //! @cond Doxygen_Suppress
    4402             : OGRErr
    4403         837 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
    4404             : 
    4405             : {
    4406             : #ifdef HAVE_MITAB
    4407             :     OGRErr eErr;
    4408             : 
    4409         837 :     if (m_poAttrIndex != nullptr)
    4410         663 :         return OGRERR_NONE;
    4411             : 
    4412         174 :     m_poAttrIndex = OGRCreateDefaultLayerIndex();
    4413             : 
    4414         174 :     eErr = m_poAttrIndex->Initialize(pszFilename, this);
    4415         174 :     if (eErr != OGRERR_NONE)
    4416             :     {
    4417           0 :         delete m_poAttrIndex;
    4418           0 :         m_poAttrIndex = nullptr;
    4419             :     }
    4420             : 
    4421         174 :     return eErr;
    4422             : #else
    4423             :     return OGRERR_FAILURE;
    4424             : #endif
    4425             : }
    4426             : 
    4427             : //! @endcond
    4428             : 
    4429             : /************************************************************************/
    4430             : /*                             SyncToDisk()                             */
    4431             : /************************************************************************/
    4432             : 
    4433             : /**
    4434             : \brief Flush pending changes to disk.
    4435             : 
    4436             : This call is intended to force the layer to flush any pending writes to
    4437             : disk, and leave the disk file in a consistent state.  It would not normally
    4438             : have any effect on read-only datasources.
    4439             : 
    4440             : Some layers do not implement this method, and will still return
    4441             : OGRERR_NONE.  The default implementation just returns OGRERR_NONE.  An error
    4442             : is only returned if an error occurs while attempting to flush to disk.
    4443             : 
    4444             : In any event, you should always close any opened datasource with
    4445             : OGRDataSource::DestroyDataSource() that will ensure all data is correctly flushed.
    4446             : 
    4447             : This method is the same as the C function OGR_L_SyncToDisk().
    4448             : 
    4449             : @return OGRERR_NONE if no error occurs (even if nothing is done) or an
    4450             : error code.
    4451             : */
    4452             : 
    4453        6568 : OGRErr OGRLayer::SyncToDisk()
    4454             : 
    4455             : {
    4456        6568 :     return OGRERR_NONE;
    4457             : }
    4458             : 
    4459             : /************************************************************************/
    4460             : /*                          OGR_L_SyncToDisk()                          */
    4461             : /************************************************************************/
    4462             : 
    4463             : /**
    4464             : \brief Flush pending changes to disk.
    4465             : 
    4466             : This call is intended to force the layer to flush any pending writes to
    4467             : disk, and leave the disk file in a consistent state.  It would not normally
    4468             : have any effect on read-only datasources.
    4469             : 
    4470             : Some layers do not implement this method, and will still return
    4471             : OGRERR_NONE.  The default implementation just returns OGRERR_NONE.  An error
    4472             : is only returned if an error occurs while attempting to flush to disk.
    4473             : 
    4474             : In any event, you should always close any opened datasource with
    4475             : OGR_DS_Destroy() that will ensure all data is correctly flushed.
    4476             : 
    4477             : This method is the same as the C++ method OGRLayer::SyncToDisk()
    4478             : 
    4479             : @param hLayer handle to the layer
    4480             : 
    4481             : @return OGRERR_NONE if no error occurs (even if nothing is done) or an
    4482             : error code.
    4483             : */
    4484             : 
    4485         251 : OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
    4486             : 
    4487             : {
    4488         251 :     VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
    4489             : 
    4490             : #ifdef OGRAPISPY_ENABLED
    4491         251 :     if (bOGRAPISpyEnabled)
    4492           2 :         OGRAPISpy_L_SyncToDisk(hLayer);
    4493             : #endif
    4494             : 
    4495         251 :     return OGRLayer::FromHandle(hLayer)->SyncToDisk();
    4496             : }
    4497             : 
    4498             : /************************************************************************/
    4499             : /*                           DeleteFeature()                            */
    4500             : /************************************************************************/
    4501             : 
    4502             : /**
    4503             :  \brief Delete feature from layer.
    4504             : 
    4505             :  The feature with the indicated feature id is deleted from the layer if
    4506             :  supported by the driver.  Most drivers do not support feature deletion,
    4507             :  and will return OGRERR_UNSUPPORTED_OPERATION.  The TestCapability()
    4508             :  layer method may be called with OLCDeleteFeature to check if the driver
    4509             :  supports feature deletion.
    4510             : 
    4511             :  This method is the same as the C function OGR_L_DeleteFeature().
    4512             : 
    4513             :  @param nFID the feature id to be deleted from the layer
    4514             : 
    4515             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    4516             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    4517             : 
    4518             : */
    4519             : 
    4520         432 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
    4521             : {
    4522         432 :     return OGRERR_UNSUPPORTED_OPERATION;
    4523             : }
    4524             : 
    4525             : /************************************************************************/
    4526             : /*                        OGR_L_DeleteFeature()                         */
    4527             : /************************************************************************/
    4528             : 
    4529             : /**
    4530             :  \brief Delete feature from layer.
    4531             : 
    4532             :  The feature with the indicated feature id is deleted from the layer if
    4533             :  supported by the driver.  Most drivers do not support feature deletion,
    4534             :  and will return OGRERR_UNSUPPORTED_OPERATION.  The OGR_L_TestCapability()
    4535             :  function may be called with OLCDeleteFeature to check if the driver
    4536             :  supports feature deletion.
    4537             : 
    4538             :  This method is the same as the C++ method OGRLayer::DeleteFeature().
    4539             : 
    4540             :  @param hLayer handle to the layer
    4541             :  @param nFID the feature id to be deleted from the layer
    4542             : 
    4543             :  @return OGRERR_NONE if the operation works, otherwise an appropriate error
    4544             :  code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
    4545             : */
    4546             : 
    4547        3356 : OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
    4548             : 
    4549             : {
    4550        3356 :     VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
    4551             : 
    4552             : #ifdef OGRAPISPY_ENABLED
    4553        3356 :     if (bOGRAPISpyEnabled)
    4554           2 :         OGRAPISpy_L_DeleteFeature(hLayer, nFID);
    4555             : #endif
    4556             : 
    4557        3356 :     return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
    4558             : }
    4559             : 
    4560             : /************************************************************************/
    4561             : /*                          GetFeaturesRead()                           */
    4562             : /************************************************************************/
    4563             : 
    4564             : //! @cond Doxygen_Suppress
    4565           0 : GIntBig OGRLayer::GetFeaturesRead()
    4566             : 
    4567             : {
    4568           0 :     return m_nFeaturesRead;
    4569             : }
    4570             : 
    4571             : //! @endcond
    4572             : 
    4573             : /************************************************************************/
    4574             : /*                       OGR_L_GetFeaturesRead()                        */
    4575             : /************************************************************************/
    4576             : 
    4577           0 : GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
    4578             : 
    4579             : {
    4580           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
    4581             : 
    4582           0 :     return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
    4583             : }
    4584             : 
    4585             : /************************************************************************/
    4586             : /*                             GetFIDColumn                             */
    4587             : /************************************************************************/
    4588             : 
    4589             : /**
    4590             :  \brief This method returns the name of the underlying database column being used as the FID column, or "" if not supported.
    4591             : 
    4592             :  This method is the same as the C function OGR_L_GetFIDColumn().
    4593             : 
    4594             :  @return fid column name.
    4595             : */
    4596             : 
    4597        9668 : const char *OGRLayer::GetFIDColumn() const
    4598             : 
    4599             : {
    4600        9668 :     return "";
    4601             : }
    4602             : 
    4603             : /************************************************************************/
    4604             : /*                         OGR_L_GetFIDColumn()                         */
    4605             : /************************************************************************/
    4606             : 
    4607             : /**
    4608             :  \brief This method returns the name of the underlying database column being used as the FID column, or "" if not supported.
    4609             : 
    4610             :  This method is the same as the C++ method OGRLayer::GetFIDColumn()
    4611             : 
    4612             :  @param hLayer handle to the layer
    4613             :  @return fid column name.
    4614             : */
    4615             : 
    4616         423 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
    4617             : 
    4618             : {
    4619         423 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
    4620             : 
    4621             : #ifdef OGRAPISPY_ENABLED
    4622         423 :     if (bOGRAPISpyEnabled)
    4623           2 :         OGRAPISpy_L_GetFIDColumn(hLayer);
    4624             : #endif
    4625             : 
    4626         423 :     return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
    4627             : }
    4628             : 
    4629             : /************************************************************************/
    4630             : /*                         GetGeometryColumn()                          */
    4631             : /************************************************************************/
    4632             : 
    4633             : /**
    4634             :  \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
    4635             : 
    4636             :  For layers with multiple geometry fields, this method only returns the name
    4637             :  of the first geometry column. For other columns, use
    4638             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetNameRef().
    4639             : 
    4640             :  This method is the same as the C function OGR_L_GetGeometryColumn().
    4641             : 
    4642             :  @return geometry column name.
    4643             : */
    4644             : 
    4645        3880 : const char *OGRLayer::GetGeometryColumn() const
    4646             : 
    4647             : {
    4648        3880 :     const auto poLayerDefn = GetLayerDefn();
    4649        3880 :     if (poLayerDefn->GetGeomFieldCount() > 0)
    4650        3788 :         return poLayerDefn->GetGeomFieldDefn(0)->GetNameRef();
    4651             :     else
    4652          92 :         return "";
    4653             : }
    4654             : 
    4655             : /************************************************************************/
    4656             : /*                      OGR_L_GetGeometryColumn()                       */
    4657             : /************************************************************************/
    4658             : 
    4659             : /**
    4660             :  \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
    4661             : 
    4662             :  For layers with multiple geometry fields, this method only returns the geometry
    4663             :  type of the first geometry column. For other columns, use
    4664             :  OGR_GFld_GetNameRef(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
    4665             : 
    4666             :  This method is the same as the C++ method OGRLayer::GetGeometryColumn()
    4667             : 
    4668             :  @param hLayer handle to the layer
    4669             :  @return geometry column name.
    4670             : */
    4671             : 
    4672         703 : const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
    4673             : 
    4674             : {
    4675         703 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
    4676             : 
    4677             : #ifdef OGRAPISPY_ENABLED
    4678         703 :     if (bOGRAPISpyEnabled)
    4679           2 :         OGRAPISpy_L_GetGeometryColumn(hLayer);
    4680             : #endif
    4681             : 
    4682         703 :     return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
    4683             : }
    4684             : 
    4685             : /************************************************************************/
    4686             : /*                           GetStyleTable()                            */
    4687             : /************************************************************************/
    4688             : 
    4689             : /**
    4690             :  \brief Returns layer style table.
    4691             : 
    4692             :  This method is the same as the C function OGR_L_GetStyleTable().
    4693             : 
    4694             :  @return pointer to a style table which should not be modified or freed by the
    4695             :  caller.
    4696             : */
    4697             : 
    4698        1210 : OGRStyleTable *OGRLayer::GetStyleTable()
    4699             : {
    4700        1210 :     return m_poStyleTable;
    4701             : }
    4702             : 
    4703             : /************************************************************************/
    4704             : /*                       SetStyleTableDirectly()                        */
    4705             : /************************************************************************/
    4706             : 
    4707             : /**
    4708             :  \brief Set layer style table.
    4709             : 
    4710             :  This method operate exactly as OGRLayer::SetStyleTable() except that it
    4711             :  assumes ownership of the passed table.
    4712             : 
    4713             :  This method is the same as the C function OGR_L_SetStyleTableDirectly().
    4714             : 
    4715             :  @param poStyleTable pointer to style table to set
    4716             : */
    4717             : 
    4718           0 : void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
    4719             : {
    4720           0 :     if (m_poStyleTable)
    4721           0 :         delete m_poStyleTable;
    4722           0 :     m_poStyleTable = poStyleTable;
    4723           0 : }
    4724             : 
    4725             : /************************************************************************/
    4726             : /*                           SetStyleTable()                            */
    4727             : /************************************************************************/
    4728             : 
    4729             : /**
    4730             :  \brief Set layer style table.
    4731             : 
    4732             :  This method operate exactly as OGRLayer::SetStyleTableDirectly() except
    4733             :  that it does not assume ownership of the passed table.
    4734             : 
    4735             :  This method is the same as the C function OGR_L_SetStyleTable().
    4736             : 
    4737             :  @param poStyleTable pointer to style table to set
    4738             : */
    4739             : 
    4740        1207 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
    4741             : {
    4742        1207 :     if (m_poStyleTable)
    4743           0 :         delete m_poStyleTable;
    4744        1207 :     if (poStyleTable)
    4745           1 :         m_poStyleTable = poStyleTable->Clone();
    4746        1207 : }
    4747             : 
    4748             : /************************************************************************/
    4749             : /*                        OGR_L_GetStyleTable()                         */
    4750             : /************************************************************************/
    4751             : 
    4752           3 : OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
    4753             : 
    4754             : {
    4755           3 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
    4756             : 
    4757             :     return reinterpret_cast<OGRStyleTableH>(
    4758           3 :         OGRLayer::FromHandle(hLayer)->GetStyleTable());
    4759             : }
    4760             : 
    4761             : /************************************************************************/
    4762             : /*                    OGR_L_SetStyleTableDirectly()                     */
    4763             : /************************************************************************/
    4764             : 
    4765           0 : void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
    4766             : 
    4767             : {
    4768           0 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
    4769             : 
    4770           0 :     OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
    4771           0 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    4772             : }
    4773             : 
    4774             : /************************************************************************/
    4775             : /*                        OGR_L_SetStyleTable()                         */
    4776             : /************************************************************************/
    4777             : 
    4778           1 : void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
    4779             : 
    4780             : {
    4781           1 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
    4782           1 :     VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
    4783             : 
    4784           1 :     OGRLayer::FromHandle(hLayer)->SetStyleTable(
    4785           1 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    4786             : }
    4787             : 
    4788             : /************************************************************************/
    4789             : /*                              GetName()                               */
    4790             : /************************************************************************/
    4791             : 
    4792             : /**
    4793             :  \brief Return the layer name.
    4794             : 
    4795             :  This returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName(), but for a
    4796             :  few drivers, calling GetName() directly can avoid lengthy layer
    4797             :  definition initialization.
    4798             : 
    4799             :  This method is the same as the C function OGR_L_GetName().
    4800             : 
    4801             :  If this method is derived in a driver, it must be done such that it
    4802             :  returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName().
    4803             : 
    4804             :  @return the layer name (must not been freed)
    4805             : */
    4806             : 
    4807     1509150 : const char *OGRLayer::GetName() const
    4808             : 
    4809             : {
    4810     1509150 :     return GetLayerDefn()->GetName();
    4811             : }
    4812             : 
    4813             : /************************************************************************/
    4814             : /*                           OGR_L_GetName()                            */
    4815             : /************************************************************************/
    4816             : 
    4817             : /**
    4818             :  \brief Return the layer name.
    4819             : 
    4820             :  This returns the same content as OGR_FD_GetName(OGR_L_GetLayerDefn(hLayer)),
    4821             :  but for a few drivers, calling OGR_L_GetName() directly can avoid lengthy
    4822             :  layer definition initialization.
    4823             : 
    4824             :  This function is the same as the C++ method OGRLayer::GetName().
    4825             : 
    4826             :  @param hLayer handle to the layer.
    4827             :  @return the layer name (must not been freed)
    4828             : */
    4829             : 
    4830        1348 : const char *OGR_L_GetName(OGRLayerH hLayer)
    4831             : 
    4832             : {
    4833        1348 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
    4834             : 
    4835             : #ifdef OGRAPISPY_ENABLED
    4836        1348 :     if (bOGRAPISpyEnabled)
    4837           2 :         OGRAPISpy_L_GetName(hLayer);
    4838             : #endif
    4839             : 
    4840        1348 :     return OGRLayer::FromHandle(hLayer)->GetName();
    4841             : }
    4842             : 
    4843             : /************************************************************************/
    4844             : /*                            GetGeomType()                             */
    4845             : /************************************************************************/
    4846             : 
    4847             : /**
    4848             :  \brief Return the layer geometry type.
    4849             : 
    4850             :  This returns the same result as GetLayerDefn()->OGRFeatureDefn::GetGeomType(), but for a
    4851             :  few drivers, calling GetGeomType() directly can avoid lengthy layer
    4852             :  definition initialization.
    4853             : 
    4854             :  Note that even if this method is const (since GDAL 3.12), there is no guarantee
    4855             :  it can be safely called by concurrent threads on the same GDALDataset object.
    4856             : 
    4857             :  For layers with multiple geometry fields, this method only returns the geometry
    4858             :  type of the first geometry column. For other columns, use
    4859             :  GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetType().
    4860             :  For layers without any geometry field, this method returns wkbNone.
    4861             : 
    4862             :  This method is the same as the C function OGR_L_GetGeomType().
    4863             : 
    4864             :  If this method is derived in a driver, it must be done such that it
    4865             :  returns the same content as GetLayerDefn()->OGRFeatureDefn::GetGeomType().
    4866             : 
    4867             :  @return the geometry type
    4868             : */
    4869             : 
    4870      219716 : OGRwkbGeometryType OGRLayer::GetGeomType() const
    4871             : {
    4872      219716 :     const OGRFeatureDefn *poLayerDefn = GetLayerDefn();
    4873      219716 :     if (poLayerDefn == nullptr)
    4874             :     {
    4875           0 :         CPLDebug("OGR", "GetLayerType() returns NULL !");
    4876           0 :         return wkbUnknown;
    4877             :     }
    4878      219716 :     return poLayerDefn->GetGeomType();
    4879             : }
    4880             : 
    4881             : /************************************************************************/
    4882             : /*                         OGR_L_GetGeomType()                          */
    4883             : /************************************************************************/
    4884             : 
    4885             : /**
    4886             :  \brief Return the layer geometry type.
    4887             : 
    4888             :  This returns the same result as OGR_FD_GetGeomType(OGR_L_GetLayerDefn(hLayer)),
    4889             :  but for a few drivers, calling OGR_L_GetGeomType() directly can avoid lengthy
    4890             :  layer definition initialization.
    4891             : 
    4892             :  For layers with multiple geometry fields, this method only returns the geometry
    4893             :  type of the first geometry column. For other columns, use
    4894             :  OGR_GFld_GetType(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
    4895             :  For layers without any geometry field, this method returns wkbNone.
    4896             : 
    4897             :  This function is the same as the C++ method OGRLayer::GetGeomType().
    4898             : 
    4899             :  @param hLayer handle to the layer.
    4900             :  @return the geometry type
    4901             : */
    4902             : 
    4903        1327 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
    4904             : 
    4905             : {
    4906        1327 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
    4907             : 
    4908             : #ifdef OGRAPISPY_ENABLED
    4909        1327 :     if (bOGRAPISpyEnabled)
    4910           2 :         OGRAPISpy_L_GetGeomType(hLayer);
    4911             : #endif
    4912             : 
    4913        1327 :     OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
    4914        1327 :     if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
    4915             :     {
    4916           1 :         eType = OGR_GT_GetLinear(eType);
    4917             :     }
    4918        1327 :     return eType;
    4919             : }
    4920             : 
    4921             : /************************************************************************/
    4922             : /*                          SetIgnoredFields()                          */
    4923             : /************************************************************************/
    4924             : 
    4925             : /**
    4926             :  \brief Set which fields can be omitted when retrieving features from the layer.
    4927             : 
    4928             :  If the driver supports this functionality (testable using OLCIgnoreFields capability), it will not fetch the specified fields
    4929             :  in subsequent calls to GetFeature() / GetNextFeature() and thus save some processing time and/or bandwidth.
    4930             : 
    4931             :  Besides field names of the layers, the following special fields can be passed: "OGR_GEOMETRY" to ignore geometry and
    4932             :  "OGR_STYLE" to ignore layer style.
    4933             : 
    4934             :  By default, no fields are ignored.
    4935             : 
    4936             :  Note that fields that are used in an attribute filter should generally not be set as
    4937             :  ignored fields, as most drivers (such as those relying on the OGR SQL engine)
    4938             :  will be unable to correctly evaluate the attribute filter.
    4939             : 
    4940             :  This method is the same as the C function OGR_L_SetIgnoredFields()
    4941             : 
    4942             :  @param papszFields an array of field names terminated by NULL item. If NULL is passed, the ignored list is cleared.
    4943             :  @return OGRERR_NONE if all field names have been resolved (even if the driver does not support this method)
    4944             : */
    4945             : 
    4946        8293 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
    4947             : {
    4948        8293 :     OGRFeatureDefn *poDefn = GetLayerDefn();
    4949             : 
    4950             :     // first set everything as *not* ignored
    4951       62377 :     for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
    4952             :     {
    4953       54084 :         poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
    4954             :     }
    4955       17506 :     for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
    4956             :     {
    4957        9213 :         poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
    4958             :     }
    4959        8293 :     poDefn->SetStyleIgnored(FALSE);
    4960             : 
    4961             :     // ignore some fields
    4962       13909 :     for (const char *pszFieldName : cpl::Iterate(papszFields))
    4963             :     {
    4964             :         // check special fields
    4965        5616 :         if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
    4966         161 :             poDefn->SetGeometryIgnored(TRUE);
    4967        5455 :         else if (EQUAL(pszFieldName, "OGR_STYLE"))
    4968          13 :             poDefn->SetStyleIgnored(TRUE);
    4969             :         else
    4970             :         {
    4971             :             // check ordinary fields
    4972        5442 :             int iField = poDefn->GetFieldIndex(pszFieldName);
    4973        5442 :             if (iField == -1)
    4974             :             {
    4975             :                 // check geometry field
    4976        1043 :                 iField = poDefn->GetGeomFieldIndex(pszFieldName);
    4977        1043 :                 if (iField == -1)
    4978             :                 {
    4979           0 :                     return OGRERR_FAILURE;
    4980             :                 }
    4981             :                 else
    4982        1043 :                     poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
    4983             :             }
    4984             :             else
    4985        4399 :                 poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
    4986             :         }
    4987             :     }
    4988             : 
    4989        8293 :     return OGRERR_NONE;
    4990             : }
    4991             : 
    4992             : /************************************************************************/
    4993             : /*                       OGR_L_SetIgnoredFields()                       */
    4994             : /************************************************************************/
    4995             : 
    4996             : /**
    4997             :  \brief Set which fields can be omitted when retrieving features from the layer.
    4998             : 
    4999             :  If the driver supports this functionality (testable using OLCIgnoreFields capability), it will not fetch the specified fields
    5000             :  in subsequent calls to GetFeature() / GetNextFeature() and thus save some processing time and/or bandwidth.
    5001             : 
    5002             :  Besides field names of the layers, the following special fields can be passed: "OGR_GEOMETRY" to ignore geometry and
    5003             :  "OGR_STYLE" to ignore layer style.
    5004             : 
    5005             :  By default, no fields are ignored.
    5006             : 
    5007             :  Note that fields that are used in an attribute filter should generally not be set as
    5008             :  ignored fields, as most drivers (such as those relying on the OGR SQL engine)
    5009             :  will be unable to correctly evaluate the attribute filter.
    5010             : 
    5011             :  This method is the same as the C++ method OGRLayer::SetIgnoredFields()
    5012             : 
    5013             :  @param hLayer handle to the layer
    5014             :  @param papszFields an array of field names terminated by NULL item. If NULL is passed, the ignored list is cleared.
    5015             :  @return OGRERR_NONE if all field names have been resolved (even if the driver does not support this method)
    5016             : */
    5017             : 
    5018         322 : OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
    5019             : 
    5020             : {
    5021         322 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
    5022             : 
    5023             : #ifdef OGRAPISPY_ENABLED
    5024         322 :     if (bOGRAPISpyEnabled)
    5025           2 :         OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
    5026             : #endif
    5027             : 
    5028         322 :     return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
    5029             : }
    5030             : 
    5031             : /************************************************************************/
    5032             : /*                               Rename()                               */
    5033             : /************************************************************************/
    5034             : 
    5035             : /** Rename layer.
    5036             :  *
    5037             :  * This operation is implemented only by layers that expose the OLCRename
    5038             :  * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
    5039             :  *
    5040             :  * This operation will fail if a layer with the new name already exists.
    5041             :  *
    5042             :  * On success, GetDescription() and GetLayerDefn()->GetName() will return
    5043             :  * pszNewName.
    5044             :  *
    5045             :  * Renaming the layer may interrupt current feature iteration.
    5046             :  *
    5047             :  * @param pszNewName New layer name. Must not be NULL.
    5048             :  * @return OGRERR_NONE in case of success
    5049             :  *
    5050             :  * @since GDAL 3.5
    5051             :  */
    5052           0 : OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
    5053             : {
    5054           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    5055             :              "Rename() not supported by this layer.");
    5056             : 
    5057           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    5058             : }
    5059             : 
    5060             : /************************************************************************/
    5061             : /*                            OGR_L_Rename()                            */
    5062             : /************************************************************************/
    5063             : 
    5064             : /** Rename layer.
    5065             :  *
    5066             :  * This operation is implemented only by layers that expose the OLCRename
    5067             :  * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
    5068             :  *
    5069             :  * This operation will fail if a layer with the new name already exists.
    5070             :  *
    5071             :  * On success, GetDescription() and GetLayerDefn()->GetName() will return
    5072             :  * pszNewName.
    5073             :  *
    5074             :  * Renaming the layer may interrupt current feature iteration.
    5075             :  *
    5076             :  * @param hLayer     Layer to rename.
    5077             :  * @param pszNewName New layer name. Must not be NULL.
    5078             :  * @return OGRERR_NONE in case of success
    5079             :  *
    5080             :  * @since GDAL 3.5
    5081             :  */
    5082          30 : OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
    5083             : 
    5084             : {
    5085          30 :     VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
    5086          30 :     VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
    5087             : 
    5088          30 :     return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
    5089             : }
    5090             : 
    5091             : /************************************************************************/
    5092             : /*              helper functions for layer overlay methods              */
    5093             : /************************************************************************/
    5094             : 
    5095          78 : static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
    5096             : {
    5097          78 :     OGRErr ret = OGRERR_NONE;
    5098          78 :     OGRGeometry *g = pLayer->GetSpatialFilter();
    5099          78 :     *ppGeometry = g ? g->clone() : nullptr;
    5100          78 :     return ret;
    5101             : }
    5102             : 
    5103          99 : static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
    5104             : {
    5105          99 :     OGRErr ret = OGRERR_NONE;
    5106          99 :     int n = poDefn->GetFieldCount();
    5107          99 :     if (n > 0)
    5108             :     {
    5109          71 :         *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
    5110          71 :         if (!(*map))
    5111           0 :             return OGRERR_NOT_ENOUGH_MEMORY;
    5112         211 :         for (int i = 0; i < n; i++)
    5113         140 :             (*map)[i] = -1;
    5114             :     }
    5115          99 :     return ret;
    5116             : }
    5117             : 
    5118          55 : static OGRErr set_result_schema(OGRLayer *pLayerResult,
    5119             :                                 OGRFeatureDefn *poDefnInput,
    5120             :                                 OGRFeatureDefn *poDefnMethod, int *mapInput,
    5121             :                                 int *mapMethod, bool combined,
    5122             :                                 const char *const *papszOptions)
    5123             : {
    5124          55 :     if (!CPLTestBool(CSLFetchNameValueDef(papszOptions, "ADD_FIELDS", "YES")))
    5125           0 :         return OGRERR_NONE;
    5126             : 
    5127          55 :     OGRErr ret = OGRERR_NONE;
    5128          55 :     OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
    5129             :     const char *pszInputPrefix =
    5130          55 :         CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
    5131             :     const char *pszMethodPrefix =
    5132          55 :         CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
    5133             :     const bool bSkipFailures =
    5134          55 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    5135          55 :     if (poDefnResult->GetFieldCount() > 0)
    5136             :     {
    5137             :         // the user has defined the schema of the output layer
    5138          17 :         if (mapInput)
    5139             :         {
    5140          48 :             for (int iField = 0; iField < poDefnInput->GetFieldCount();
    5141             :                  iField++)
    5142             :             {
    5143             :                 CPLString osName(
    5144          31 :                     poDefnInput->GetFieldDefn(iField)->GetNameRef());
    5145          31 :                 if (pszInputPrefix != nullptr)
    5146          17 :                     osName = pszInputPrefix + osName;
    5147          31 :                 mapInput[iField] = poDefnResult->GetFieldIndex(osName);
    5148             :             }
    5149             :         }
    5150          17 :         if (!mapMethod)
    5151           4 :             return ret;
    5152             :         // cppcheck-suppress nullPointer
    5153          40 :         for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
    5154             :         {
    5155             :             // cppcheck-suppress nullPointer
    5156          27 :             CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
    5157          27 :             if (pszMethodPrefix != nullptr)
    5158          17 :                 osName = pszMethodPrefix + osName;
    5159          27 :             mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
    5160             :         }
    5161             :     }
    5162             :     else
    5163             :     {
    5164             :         // use schema from the input layer or from input and method layers
    5165          38 :         const int nFieldsInput = poDefnInput->GetFieldCount();
    5166             : 
    5167             :         // If no prefix is specified and we have input+method layers, make
    5168             :         // sure we will generate unique field names
    5169          38 :         std::set<std::string> oSetInputFieldNames;
    5170          38 :         std::set<std::string> oSetMethodFieldNames;
    5171          38 :         if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
    5172             :             pszMethodPrefix == nullptr)
    5173             :         {
    5174          67 :             for (int iField = 0; iField < nFieldsInput; iField++)
    5175             :             {
    5176             :                 oSetInputFieldNames.insert(
    5177          36 :                     poDefnInput->GetFieldDefn(iField)->GetNameRef());
    5178             :             }
    5179          31 :             const int nFieldsMethod = poDefnMethod->GetFieldCount();
    5180          65 :             for (int iField = 0; iField < nFieldsMethod; iField++)
    5181             :             {
    5182             :                 oSetMethodFieldNames.insert(
    5183          34 :                     poDefnMethod->GetFieldDefn(iField)->GetNameRef());
    5184             :             }
    5185             :         }
    5186             : 
    5187          38 :         const bool bAddInputFields = CPLTestBool(
    5188             :             CSLFetchNameValueDef(papszOptions, "ADD_INPUT_FIELDS", "YES"));
    5189          38 :         if (bAddInputFields)
    5190             :         {
    5191          70 :             for (int iField = 0; iField < nFieldsInput; iField++)
    5192             :             {
    5193          36 :                 OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
    5194          36 :                 if (pszInputPrefix != nullptr)
    5195           0 :                     oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
    5196             :                                                   oFieldDefn.GetNameRef()));
    5197          58 :                 else if (!oSetMethodFieldNames.empty() &&
    5198          58 :                          oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
    5199          58 :                              oSetMethodFieldNames.end())
    5200             :                 {
    5201             :                     // Field of same name present in method layer
    5202          13 :                     oFieldDefn.SetName(
    5203             :                         CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
    5204             :                 }
    5205          36 :                 ret = pLayerResult->CreateField(&oFieldDefn);
    5206          36 :                 if (ret != OGRERR_NONE)
    5207             :                 {
    5208           0 :                     if (!bSkipFailures)
    5209           0 :                         return ret;
    5210             :                     else
    5211             :                     {
    5212           0 :                         CPLErrorReset();
    5213           0 :                         ret = OGRERR_NONE;
    5214             :                     }
    5215             :                 }
    5216          36 :                 if (mapInput)
    5217          36 :                     mapInput[iField] =
    5218          36 :                         pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
    5219             :             }
    5220             :         }
    5221             : 
    5222          38 :         if (!combined)
    5223          11 :             return ret;
    5224          27 :         if (!mapMethod)
    5225          12 :             return ret;
    5226          15 :         if (!poDefnMethod)
    5227           0 :             return ret;
    5228             : 
    5229          15 :         const bool bAddMethodFields = CPLTestBool(
    5230             :             CSLFetchNameValueDef(papszOptions, "ADD_METHOD_FIELDS", "YES"));
    5231          15 :         if (bAddMethodFields)
    5232             :         {
    5233          11 :             const int nFieldsMethod = poDefnMethod->GetFieldCount();
    5234          29 :             for (int iField = 0; iField < nFieldsMethod; iField++)
    5235             :             {
    5236          18 :                 OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
    5237          18 :                 if (pszMethodPrefix != nullptr)
    5238           0 :                     oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
    5239             :                                                   oFieldDefn.GetNameRef()));
    5240          36 :                 else if (!oSetInputFieldNames.empty() &&
    5241          36 :                          oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
    5242          36 :                              oSetInputFieldNames.end())
    5243             :                 {
    5244             :                     // Field of same name present in method layer
    5245          11 :                     oFieldDefn.SetName(
    5246             :                         CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
    5247             :                 }
    5248          18 :                 ret = pLayerResult->CreateField(&oFieldDefn);
    5249          18 :                 if (ret != OGRERR_NONE)
    5250             :                 {
    5251           0 :                     if (!bSkipFailures)
    5252           0 :                         return ret;
    5253             :                     else
    5254             :                     {
    5255           0 :                         CPLErrorReset();
    5256           0 :                         ret = OGRERR_NONE;
    5257             :                     }
    5258             :                 }
    5259          18 :                 mapMethod[iField] =
    5260          18 :                     pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
    5261             :             }
    5262             :         }
    5263             :     }
    5264          28 :     return ret;
    5265             : }
    5266             : 
    5267         309 : static OGRGeometry *set_filter_from(OGRLayer *pLayer,
    5268             :                                     OGRGeometry *pGeometryExistingFilter,
    5269             :                                     OGRFeature *pFeature)
    5270             : {
    5271         309 :     OGRGeometry *geom = pFeature->GetGeometryRef();
    5272         309 :     if (!geom)
    5273           0 :         return nullptr;
    5274         309 :     if (pGeometryExistingFilter)
    5275             :     {
    5276           0 :         if (!geom->Intersects(pGeometryExistingFilter))
    5277           0 :             return nullptr;
    5278           0 :         OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
    5279           0 :         if (intersection)
    5280             :         {
    5281           0 :             pLayer->SetSpatialFilter(intersection);
    5282           0 :             delete intersection;
    5283             :         }
    5284             :         else
    5285           0 :             return nullptr;
    5286             :     }
    5287             :     else
    5288             :     {
    5289         309 :         pLayer->SetSpatialFilter(geom);
    5290             :     }
    5291         309 :     return geom;
    5292             : }
    5293             : 
    5294          26 : static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
    5295             : {
    5296          26 :     OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    5297          26 :     if (eType == wkbPoint)
    5298           4 :         return OGRGeometryFactory::forceToMultiPoint(poGeom);
    5299          22 :     else if (eType == wkbPolygon)
    5300          22 :         return OGRGeometryFactory::forceToMultiPolygon(poGeom);
    5301           0 :     else if (eType == wkbLineString)
    5302           0 :         return OGRGeometryFactory::forceToMultiLineString(poGeom);
    5303             :     else
    5304           0 :         return poGeom;
    5305             : }
    5306             : 
    5307             : /************************************************************************/
    5308             : /*                            Intersection()                            */
    5309             : /************************************************************************/
    5310             : /**
    5311             :  * \brief Intersection of two layers.
    5312             :  *
    5313             :  * The result layer contains features whose geometries represent areas
    5314             :  * that are common between features in the input layer and in the
    5315             :  * method layer. The features in the result layer have attributes from
    5316             :  * both input and method layers. The schema of the result layer can be
    5317             :  * set by the user or, if it is empty, is initialized to contain all
    5318             :  * fields in the input and method layers.
    5319             :  *
    5320             :  * \note If the schema of the result is set by user and contains
    5321             :  * fields that have the same name as a field in input and in method
    5322             :  * layer, then the attribute in the result feature will get the value
    5323             :  * from the feature of the method layer.
    5324             :  *
    5325             :  * \note For best performance use the minimum amount of features in
    5326             :  * the method layer and copy it into a memory layer.
    5327             :  *
    5328             :  * \note This method relies on GEOS support. Do not use unless the
    5329             :  * GEOS support is compiled in.
    5330             :  *
    5331             :  * The recognized list of options is:
    5332             :  * <ul>
    5333             :  * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
    5334             :  *     feature could not be inserted or a GEOS call failed.
    5335             :  * </li>
    5336             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5337             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5338             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5339             :  * </li>
    5340             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5341             :  *     will be created from the fields of the input layer.
    5342             :  * </li>
    5343             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5344             :  *     will be created from the fields of the method layer.
    5345             :  * </li>
    5346             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    5347             :  *     geometries to pretest intersection of features of method layer
    5348             :  *     with features of this layer.
    5349             :  * </li>
    5350             :  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
    5351             :  *     containment of features of method layer within the features of
    5352             :  *     this layer. This will speed up the method significantly in some
    5353             :  *     cases. Requires that the prepared geometries are in effect.
    5354             :  * </li>
    5355             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    5356             :  *     result features with lower dimension geometry that would
    5357             :  *     otherwise be added to the result layer. The default is YES, to add
    5358             :  *     features with lower dimension geometry, but only if the result layer
    5359             :  *     has an unknown geometry type.
    5360             :  * </li>
    5361             :  * </ul>
    5362             :  *
    5363             :  * This method is the same as the C function OGR_L_Intersection().
    5364             :  *
    5365             :  * @param pLayerMethod the method layer. Should not be NULL.
    5366             :  *
    5367             :  * @param pLayerResult the layer where the features resulting from the
    5368             :  * operation are inserted. Should not be NULL. See above the note
    5369             :  * about the schema.
    5370             :  *
    5371             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5372             :  *
    5373             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5374             :  * reporting progress or NULL.
    5375             :  *
    5376             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5377             :  *
    5378             :  * @return an error code if there was an error or the execution was
    5379             :  * interrupted, OGRERR_NONE otherwise.
    5380             :  *
    5381             :  * @note The first geometry field is always used.
    5382             :  *
    5383             :  * @since OGR 1.10
    5384             :  */
    5385             : 
    5386           8 : OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    5387             :                               CSLConstList papszOptions,
    5388             :                               GDALProgressFunc pfnProgress, void *pProgressArg)
    5389             : {
    5390           8 :     OGRErr ret = OGRERR_NONE;
    5391           8 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    5392           8 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    5393           8 :     OGRFeatureDefn *poDefnResult = nullptr;
    5394           8 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    5395           8 :     int *mapInput = nullptr;
    5396           8 :     int *mapMethod = nullptr;
    5397           8 :     OGREnvelope sEnvelopeMethod;
    5398             :     GBool bEnvelopeSet;
    5399           8 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    5400           8 :     double progress_counter = 0;
    5401           8 :     double progress_ticker = 0;
    5402             :     const bool bSkipFailures =
    5403           8 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    5404           8 :     const bool bPromoteToMulti = CPLTestBool(
    5405             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    5406           8 :     const bool bUsePreparedGeometries = CPLTestBool(
    5407             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    5408           8 :     const bool bPretestContainment = CPLTestBool(
    5409             :         CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
    5410           8 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    5411             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    5412             : 
    5413             :     // check for GEOS
    5414           8 :     if (!OGRGeometryFactory::haveGEOS())
    5415             :     {
    5416           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    5417             :                  "OGRLayer::Intersection() requires GEOS support");
    5418           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    5419             :     }
    5420             : 
    5421             :     // get resources
    5422           8 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    5423           8 :     if (ret != OGRERR_NONE)
    5424           0 :         goto done;
    5425           8 :     ret = create_field_map(poDefnInput, &mapInput);
    5426           8 :     if (ret != OGRERR_NONE)
    5427           0 :         goto done;
    5428           8 :     ret = create_field_map(poDefnMethod, &mapMethod);
    5429           8 :     if (ret != OGRERR_NONE)
    5430           0 :         goto done;
    5431           8 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    5432             :                             mapMethod, true, papszOptions);
    5433           8 :     if (ret != OGRERR_NONE)
    5434           0 :         goto done;
    5435           8 :     poDefnResult = pLayerResult->GetLayerDefn();
    5436           8 :     bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
    5437           8 :     if (bKeepLowerDimGeom)
    5438             :     {
    5439             :         // require that the result layer is of geom type unknown
    5440           6 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    5441             :         {
    5442           0 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    5443             :                             "since the result layer does not allow it.");
    5444           0 :             bKeepLowerDimGeom = false;
    5445             :         }
    5446             :     }
    5447             : 
    5448          23 :     for (auto &&x : this)
    5449             :     {
    5450             : 
    5451          15 :         if (pfnProgress)
    5452             :         {
    5453           2 :             double p = progress_counter / progress_max;
    5454           2 :             if (p > progress_ticker)
    5455             :             {
    5456           1 :                 if (!pfnProgress(p, "", pProgressArg))
    5457             :                 {
    5458           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5459           0 :                     ret = OGRERR_FAILURE;
    5460           0 :                     goto done;
    5461             :                 }
    5462             :             }
    5463           2 :             progress_counter += 1.0;
    5464             :         }
    5465             : 
    5466             :         // is it worth to proceed?
    5467          15 :         if (bEnvelopeSet)
    5468             :         {
    5469          15 :             OGRGeometry *x_geom = x->GetGeometryRef();
    5470          15 :             if (x_geom)
    5471             :             {
    5472          15 :                 OGREnvelope x_env;
    5473          15 :                 x_geom->getEnvelope(&x_env);
    5474          15 :                 if (x_env.MaxX < sEnvelopeMethod.MinX ||
    5475          15 :                     x_env.MaxY < sEnvelopeMethod.MinY ||
    5476          15 :                     sEnvelopeMethod.MaxX < x_env.MinX ||
    5477          15 :                     sEnvelopeMethod.MaxY < x_env.MinY)
    5478             :                 {
    5479           0 :                     continue;
    5480             :                 }
    5481             :             }
    5482             :             else
    5483             :             {
    5484           0 :                 continue;
    5485             :             }
    5486             :         }
    5487             : 
    5488             :         // set up the filter for method layer
    5489          15 :         CPLErrorReset();
    5490             :         OGRGeometry *x_geom =
    5491          15 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    5492          15 :         if (CPLGetLastErrorType() != CE_None)
    5493             :         {
    5494           0 :             if (!bSkipFailures)
    5495             :             {
    5496           0 :                 ret = OGRERR_FAILURE;
    5497           0 :                 goto done;
    5498             :             }
    5499             :             else
    5500             :             {
    5501           0 :                 CPLErrorReset();
    5502           0 :                 ret = OGRERR_NONE;
    5503             :             }
    5504             :         }
    5505          15 :         if (!x_geom)
    5506             :         {
    5507           0 :             continue;
    5508             :         }
    5509             : 
    5510           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    5511          15 :         if (bUsePreparedGeometries)
    5512             :         {
    5513          15 :             x_prepared_geom.reset(
    5514             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    5515          15 :             if (!x_prepared_geom)
    5516             :             {
    5517           0 :                 goto done;
    5518             :             }
    5519             :         }
    5520             : 
    5521          32 :         for (auto &&y : pLayerMethod)
    5522             :         {
    5523          17 :             OGRGeometry *y_geom = y->GetGeometryRef();
    5524          17 :             if (!y_geom)
    5525           4 :                 continue;
    5526           0 :             OGRGeometryUniquePtr z_geom;
    5527             : 
    5528          17 :             if (x_prepared_geom)
    5529             :             {
    5530          17 :                 CPLErrorReset();
    5531          17 :                 ret = OGRERR_NONE;
    5532          17 :                 if (bPretestContainment &&
    5533           0 :                     OGRPreparedGeometryContains(x_prepared_geom.get(),
    5534             :                                                 OGRGeometry::ToHandle(y_geom)))
    5535             :                 {
    5536           0 :                     if (CPLGetLastErrorType() == CE_None)
    5537           0 :                         z_geom.reset(y_geom->clone());
    5538             :                 }
    5539          17 :                 else if (!(OGRPreparedGeometryIntersects(
    5540             :                              x_prepared_geom.get(),
    5541             :                              OGRGeometry::ToHandle(y_geom))))
    5542             :                 {
    5543           0 :                     if (CPLGetLastErrorType() == CE_None)
    5544             :                     {
    5545           0 :                         continue;
    5546             :                     }
    5547             :                 }
    5548          17 :                 if (CPLGetLastErrorType() != CE_None)
    5549             :                 {
    5550           0 :                     if (!bSkipFailures)
    5551             :                     {
    5552           0 :                         ret = OGRERR_FAILURE;
    5553           0 :                         goto done;
    5554             :                     }
    5555             :                     else
    5556             :                     {
    5557           0 :                         CPLErrorReset();
    5558           0 :                         ret = OGRERR_NONE;
    5559           0 :                         continue;
    5560             :                     }
    5561             :                 }
    5562             :             }
    5563          17 :             if (!z_geom)
    5564             :             {
    5565          17 :                 CPLErrorReset();
    5566          17 :                 z_geom.reset(x_geom->Intersection(y_geom));
    5567          17 :                 if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
    5568             :                 {
    5569           0 :                     if (!bSkipFailures)
    5570             :                     {
    5571           0 :                         ret = OGRERR_FAILURE;
    5572           0 :                         goto done;
    5573             :                     }
    5574             :                     else
    5575             :                     {
    5576           0 :                         CPLErrorReset();
    5577           0 :                         ret = OGRERR_NONE;
    5578           0 :                         continue;
    5579             :                     }
    5580             :                 }
    5581          34 :                 if (z_geom->IsEmpty() ||
    5582          17 :                     (!bKeepLowerDimGeom &&
    5583           6 :                      (x_geom->getDimension() == y_geom->getDimension() &&
    5584           6 :                       z_geom->getDimension() < x_geom->getDimension())))
    5585             :                 {
    5586           4 :                     continue;
    5587             :                 }
    5588             :             }
    5589          13 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    5590          13 :             z->SetFieldsFrom(x.get(), mapInput);
    5591          13 :             z->SetFieldsFrom(y.get(), mapMethod);
    5592          13 :             if (bPromoteToMulti)
    5593           3 :                 z_geom.reset(promote_to_multi(z_geom.release()));
    5594          13 :             z->SetGeometryDirectly(z_geom.release());
    5595          13 :             ret = pLayerResult->CreateFeature(z.get());
    5596             : 
    5597          13 :             if (ret != OGRERR_NONE)
    5598             :             {
    5599           0 :                 if (!bSkipFailures)
    5600             :                 {
    5601           0 :                     goto done;
    5602             :                 }
    5603             :                 else
    5604             :                 {
    5605           0 :                     CPLErrorReset();
    5606           0 :                     ret = OGRERR_NONE;
    5607             :                 }
    5608             :             }
    5609             :         }
    5610             :     }
    5611           8 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    5612             :     {
    5613           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5614           0 :         ret = OGRERR_FAILURE;
    5615           0 :         goto done;
    5616             :     }
    5617           8 : done:
    5618             :     // release resources
    5619           8 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    5620           8 :     if (pGeometryMethodFilter)
    5621           0 :         delete pGeometryMethodFilter;
    5622           8 :     if (mapInput)
    5623           4 :         VSIFree(mapInput);
    5624           8 :     if (mapMethod)
    5625           4 :         VSIFree(mapMethod);
    5626           8 :     return ret;
    5627             : }
    5628             : 
    5629             : /************************************************************************/
    5630             : /*                         OGR_L_Intersection()                         */
    5631             : /************************************************************************/
    5632             : /**
    5633             :  * \brief Intersection of two layers.
    5634             :  *
    5635             :  * The result layer contains features whose geometries represent areas
    5636             :  * that are common between features in the input layer and in the
    5637             :  * method layer. The features in the result layer have attributes from
    5638             :  * both input and method layers. The schema of the result layer can be
    5639             :  * set by the user or, if it is empty, is initialized to contain all
    5640             :  * fields in the input and method layers.
    5641             :  *
    5642             :  * \note If the schema of the result is set by user and contains
    5643             :  * fields that have the same name as a field in input and in method
    5644             :  * layer, then the attribute in the result feature will get the value
    5645             :  * from the feature of the method layer.
    5646             :  *
    5647             :  * \note For best performance use the minimum amount of features in
    5648             :  * the method layer and copy it into a memory layer.
    5649             :  *
    5650             :  * \note This method relies on GEOS support. Do not use unless the
    5651             :  * GEOS support is compiled in.
    5652             :  *
    5653             :  * The recognized list of options is :
    5654             :  * <ul>
    5655             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5656             :  *     feature could not be inserted or a GEOS call failed.
    5657             :  * </li>
    5658             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5659             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5660             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5661             :  * </li>
    5662             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5663             :  *     will be created from the fields of the input layer.
    5664             :  * </li>
    5665             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5666             :  *     will be created from the fields of the method layer.
    5667             :  * </li>
    5668             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    5669             :  *     geometries to pretest intersection of features of method layer
    5670             :  *     with features of this layer.
    5671             :  * </li>
    5672             :  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
    5673             :  *     containment of features of method layer within the features of
    5674             :  *     this layer. This will speed up the method significantly in some
    5675             :  *     cases. Requires that the prepared geometries are in effect.
    5676             :  * </li>
    5677             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    5678             :  *     result features with lower dimension geometry that would
    5679             :  *     otherwise be added to the result layer. The default is YES, to add
    5680             :  *     features with lower dimension geometry, but only if the result layer
    5681             :  *     has an unknown geometry type.
    5682             :  * </li>
    5683             :  * </ul>
    5684             :  *
    5685             :  * This function is the same as the C++ method OGRLayer::Intersection().
    5686             :  *
    5687             :  * @param pLayerInput the input layer. Should not be NULL.
    5688             :  *
    5689             :  * @param pLayerMethod the method layer. Should not be NULL.
    5690             :  *
    5691             :  * @param pLayerResult the layer where the features resulting from the
    5692             :  * operation are inserted. Should not be NULL. See above the note
    5693             :  * about the schema.
    5694             :  *
    5695             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5696             :  *
    5697             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5698             :  * reporting progress or NULL.
    5699             :  *
    5700             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5701             :  *
    5702             :  * @return an error code if there was an error or the execution was
    5703             :  * interrupted, OGRERR_NONE otherwise.
    5704             :  *
    5705             :  * @note The first geometry field is always used.
    5706             :  *
    5707             :  * @since OGR 1.10
    5708             :  */
    5709             : 
    5710           7 : OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    5711             :                           OGRLayerH pLayerResult, CSLConstList papszOptions,
    5712             :                           GDALProgressFunc pfnProgress, void *pProgressArg)
    5713             : 
    5714             : {
    5715           7 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
    5716           7 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
    5717             :                       OGRERR_INVALID_HANDLE);
    5718           7 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
    5719             :                       OGRERR_INVALID_HANDLE);
    5720             : 
    5721             :     return OGRLayer::FromHandle(pLayerInput)
    5722           7 :         ->Intersection(OGRLayer::FromHandle(pLayerMethod),
    5723             :                        OGRLayer::FromHandle(pLayerResult), papszOptions,
    5724           7 :                        pfnProgress, pProgressArg);
    5725             : }
    5726             : 
    5727             : /************************************************************************/
    5728             : /*                               Union()                                */
    5729             : /************************************************************************/
    5730             : 
    5731             : /**
    5732             :  * \brief Union of two layers.
    5733             :  *
    5734             :  * The result layer contains features whose geometries represent areas
    5735             :  * that are either in the input layer, in the method layer, or in
    5736             :  * both. The features in the result layer have attributes from both
    5737             :  * input and method layers. For features which represent areas that
    5738             :  * are only in the input or in the method layer the respective
    5739             :  * attributes have undefined values. The schema of the result layer
    5740             :  * can be set by the user or, if it is empty, is initialized to
    5741             :  * contain all fields in the input and method layers.
    5742             :  *
    5743             :  * \note If the schema of the result is set by user and contains
    5744             :  * fields that have the same name as a field in input and in method
    5745             :  * layer, then the attribute in the result feature will get the value
    5746             :  * from the feature of the method layer (even if it is undefined).
    5747             :  *
    5748             :  * \note For best performance use the minimum amount of features in
    5749             :  * the method layer and copy it into a memory layer.
    5750             :  *
    5751             :  * \note This method relies on GEOS support. Do not use unless the
    5752             :  * GEOS support is compiled in.
    5753             :  *
    5754             :  * The recognized list of options is :
    5755             :  * <ul>
    5756             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5757             :  *     feature could not be inserted or a GEOS call failed.
    5758             :  * </li>
    5759             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5760             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5761             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5762             :  * </li>
    5763             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5764             :  *     will be created from the fields of the input layer.
    5765             :  * </li>
    5766             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5767             :  *     will be created from the fields of the method layer.
    5768             :  * </li>
    5769             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    5770             :  *     geometries to pretest intersection of features of method layer
    5771             :  *     with features of this layer.
    5772             :  * </li>
    5773             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    5774             :  *     result features with lower dimension geometry that would
    5775             :  *     otherwise be added to the result layer. The default is YES, to add
    5776             :  *     features with lower dimension geometry, but only if the result layer
    5777             :  *     has an unknown geometry type.
    5778             :  * </li>
    5779             :  * </ul>
    5780             :  *
    5781             :  * This method is the same as the C function OGR_L_Union().
    5782             :  *
    5783             :  * @param pLayerMethod the method layer. Should not be NULL.
    5784             :  *
    5785             :  * @param pLayerResult the layer where the features resulting from the
    5786             :  * operation are inserted. Should not be NULL. See above the note
    5787             :  * about the schema.
    5788             :  *
    5789             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5790             :  *
    5791             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5792             :  * reporting progress or NULL.
    5793             :  *
    5794             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5795             :  *
    5796             :  * @return an error code if there was an error or the execution was
    5797             :  * interrupted, OGRERR_NONE otherwise.
    5798             :  *
    5799             :  * @note The first geometry field is always used.
    5800             :  *
    5801             :  * @since OGR 1.10
    5802             :  */
    5803             : 
    5804          18 : OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    5805             :                        CSLConstList papszOptions, GDALProgressFunc pfnProgress,
    5806             :                        void *pProgressArg)
    5807             : {
    5808          18 :     OGRErr ret = OGRERR_NONE;
    5809          18 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    5810          18 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    5811          18 :     OGRFeatureDefn *poDefnResult = nullptr;
    5812          18 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    5813          18 :     OGRGeometry *pGeometryInputFilter = nullptr;
    5814          18 :     int *mapInput = nullptr;
    5815          18 :     int *mapMethod = nullptr;
    5816             :     double progress_max =
    5817          18 :         static_cast<double>(GetFeatureCount(FALSE)) +
    5818          18 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    5819          18 :     double progress_counter = 0;
    5820          18 :     double progress_ticker = 0;
    5821             :     const bool bSkipFailures =
    5822          18 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    5823          18 :     const bool bPromoteToMulti = CPLTestBool(
    5824             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    5825          18 :     const bool bUsePreparedGeometries = CPLTestBool(
    5826             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    5827          18 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    5828             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    5829             : 
    5830             :     // check for GEOS
    5831          18 :     if (!OGRGeometryFactory::haveGEOS())
    5832             :     {
    5833           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    5834             :                  "OGRLayer::Union() requires GEOS support");
    5835           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    5836             :     }
    5837             : 
    5838             :     // get resources
    5839          18 :     ret = clone_spatial_filter(this, &pGeometryInputFilter);
    5840          18 :     if (ret != OGRERR_NONE)
    5841           0 :         goto done;
    5842          18 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    5843          18 :     if (ret != OGRERR_NONE)
    5844           0 :         goto done;
    5845          18 :     ret = create_field_map(poDefnInput, &mapInput);
    5846          18 :     if (ret != OGRERR_NONE)
    5847           0 :         goto done;
    5848          18 :     ret = create_field_map(poDefnMethod, &mapMethod);
    5849          18 :     if (ret != OGRERR_NONE)
    5850           0 :         goto done;
    5851          18 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    5852             :                             mapMethod, true, papszOptions);
    5853          18 :     if (ret != OGRERR_NONE)
    5854           0 :         goto done;
    5855          18 :     poDefnResult = pLayerResult->GetLayerDefn();
    5856          18 :     if (bKeepLowerDimGeom)
    5857             :     {
    5858             :         // require that the result layer is of geom type unknown
    5859          16 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    5860             :         {
    5861          11 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    5862             :                             "since the result layer does not allow it.");
    5863          11 :             bKeepLowerDimGeom = FALSE;
    5864             :         }
    5865             :     }
    5866             : 
    5867             :     // add features based on input layer
    5868         133 :     for (auto &&x : this)
    5869             :     {
    5870             : 
    5871         115 :         if (pfnProgress)
    5872             :         {
    5873           2 :             double p = progress_counter / progress_max;
    5874           2 :             if (p > progress_ticker)
    5875             :             {
    5876           1 :                 if (!pfnProgress(p, "", pProgressArg))
    5877             :                 {
    5878           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5879           0 :                     ret = OGRERR_FAILURE;
    5880           0 :                     goto done;
    5881             :                 }
    5882             :             }
    5883           2 :             progress_counter += 1.0;
    5884             :         }
    5885             : 
    5886             :         // set up the filter on method layer
    5887         115 :         CPLErrorReset();
    5888             :         OGRGeometry *x_geom =
    5889         115 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    5890         115 :         if (CPLGetLastErrorType() != CE_None)
    5891             :         {
    5892           0 :             if (!bSkipFailures)
    5893             :             {
    5894           0 :                 ret = OGRERR_FAILURE;
    5895           0 :                 goto done;
    5896             :             }
    5897             :             else
    5898             :             {
    5899           0 :                 CPLErrorReset();
    5900           0 :                 ret = OGRERR_NONE;
    5901             :             }
    5902             :         }
    5903         115 :         if (!x_geom)
    5904             :         {
    5905           0 :             continue;
    5906             :         }
    5907             : 
    5908           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    5909         115 :         if (bUsePreparedGeometries)
    5910             :         {
    5911         115 :             x_prepared_geom.reset(
    5912             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    5913         115 :             if (!x_prepared_geom)
    5914             :             {
    5915           0 :                 goto done;
    5916             :             }
    5917             :         }
    5918             : 
    5919             :         OGRGeometryUniquePtr x_geom_diff(
    5920             :             x_geom
    5921         115 :                 ->clone());  // this will be the geometry of the result feature
    5922         631 :         for (auto &&y : pLayerMethod)
    5923             :         {
    5924         516 :             OGRGeometry *y_geom = y->GetGeometryRef();
    5925         516 :             if (!y_geom)
    5926             :             {
    5927           0 :                 continue;
    5928             :             }
    5929             : 
    5930         516 :             CPLErrorReset();
    5931        1032 :             if (x_prepared_geom &&
    5932         516 :                 !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
    5933         516 :                                                 OGRGeometry::ToHandle(y_geom))))
    5934             :             {
    5935           0 :                 if (CPLGetLastErrorType() == CE_None)
    5936             :                 {
    5937           0 :                     continue;
    5938             :                 }
    5939             :             }
    5940         516 :             if (CPLGetLastErrorType() != CE_None)
    5941             :             {
    5942           0 :                 if (!bSkipFailures)
    5943             :                 {
    5944           0 :                     ret = OGRERR_FAILURE;
    5945           0 :                     goto done;
    5946             :                 }
    5947             :                 else
    5948             :                 {
    5949           0 :                     CPLErrorReset();
    5950           0 :                     ret = OGRERR_NONE;
    5951             :                 }
    5952             :             }
    5953             : 
    5954         516 :             CPLErrorReset();
    5955         516 :             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
    5956         516 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    5957             :             {
    5958           0 :                 if (!bSkipFailures)
    5959             :                 {
    5960           0 :                     ret = OGRERR_FAILURE;
    5961           0 :                     goto done;
    5962             :                 }
    5963             :                 else
    5964             :                 {
    5965           0 :                     CPLErrorReset();
    5966           0 :                     ret = OGRERR_NONE;
    5967           0 :                     continue;
    5968             :                 }
    5969             :             }
    5970        1032 :             if (poIntersection->IsEmpty() ||
    5971         516 :                 (!bKeepLowerDimGeom &&
    5972         507 :                  (x_geom->getDimension() == y_geom->getDimension() &&
    5973         507 :                   poIntersection->getDimension() < x_geom->getDimension())))
    5974             :             {
    5975             :                 // ok
    5976             :             }
    5977             :             else
    5978             :             {
    5979         112 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    5980         112 :                 z->SetFieldsFrom(x.get(), mapInput);
    5981         112 :                 z->SetFieldsFrom(y.get(), mapMethod);
    5982         112 :                 if (bPromoteToMulti)
    5983           3 :                     poIntersection.reset(
    5984             :                         promote_to_multi(poIntersection.release()));
    5985         112 :                 z->SetGeometryDirectly(poIntersection.release());
    5986             : 
    5987         112 :                 if (x_geom_diff)
    5988             :                 {
    5989         112 :                     CPLErrorReset();
    5990             :                     OGRGeometryUniquePtr x_geom_diff_new(
    5991         112 :                         x_geom_diff->Difference(y_geom));
    5992         224 :                     if (CPLGetLastErrorType() != CE_None ||
    5993         112 :                         x_geom_diff_new == nullptr)
    5994             :                     {
    5995           0 :                         if (!bSkipFailures)
    5996             :                         {
    5997           0 :                             ret = OGRERR_FAILURE;
    5998           0 :                             goto done;
    5999             :                         }
    6000             :                         else
    6001             :                         {
    6002           0 :                             CPLErrorReset();
    6003             :                         }
    6004             :                     }
    6005             :                     else
    6006             :                     {
    6007         112 :                         x_geom_diff.swap(x_geom_diff_new);
    6008             :                     }
    6009             :                 }
    6010             : 
    6011         112 :                 ret = pLayerResult->CreateFeature(z.get());
    6012         112 :                 if (ret != OGRERR_NONE)
    6013             :                 {
    6014           0 :                     if (!bSkipFailures)
    6015             :                     {
    6016           0 :                         goto done;
    6017             :                     }
    6018             :                     else
    6019             :                     {
    6020           0 :                         CPLErrorReset();
    6021           0 :                         ret = OGRERR_NONE;
    6022             :                     }
    6023             :                 }
    6024             :             }
    6025             :         }
    6026         115 :         x_prepared_geom.reset();
    6027             : 
    6028         115 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    6029             :         {
    6030             :             // ok
    6031             :         }
    6032             :         else
    6033             :         {
    6034          12 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    6035          12 :             z->SetFieldsFrom(x.get(), mapInput);
    6036          12 :             if (bPromoteToMulti)
    6037           3 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    6038          12 :             z->SetGeometryDirectly(x_geom_diff.release());
    6039          12 :             ret = pLayerResult->CreateFeature(z.get());
    6040          12 :             if (ret != OGRERR_NONE)
    6041             :             {
    6042           0 :                 if (!bSkipFailures)
    6043             :                 {
    6044           0 :                     goto done;
    6045             :                 }
    6046             :                 else
    6047             :                 {
    6048           0 :                     CPLErrorReset();
    6049           0 :                     ret = OGRERR_NONE;
    6050             :                 }
    6051             :             }
    6052             :         }
    6053             :     }
    6054             : 
    6055             :     // restore filter on method layer and add features based on it
    6056          18 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    6057         130 :     for (auto &&x : pLayerMethod)
    6058             :     {
    6059             : 
    6060         112 :         if (pfnProgress)
    6061             :         {
    6062           1 :             double p = progress_counter / progress_max;
    6063           1 :             if (p > progress_ticker)
    6064             :             {
    6065           1 :                 if (!pfnProgress(p, "", pProgressArg))
    6066             :                 {
    6067           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6068           0 :                     ret = OGRERR_FAILURE;
    6069           0 :                     goto done;
    6070             :                 }
    6071             :             }
    6072           1 :             progress_counter += 1.0;
    6073             :         }
    6074             : 
    6075             :         // set up the filter on input layer
    6076         112 :         CPLErrorReset();
    6077             :         OGRGeometry *x_geom =
    6078         112 :             set_filter_from(this, pGeometryInputFilter, x.get());
    6079         112 :         if (CPLGetLastErrorType() != CE_None)
    6080             :         {
    6081           0 :             if (!bSkipFailures)
    6082             :             {
    6083           0 :                 ret = OGRERR_FAILURE;
    6084           0 :                 goto done;
    6085             :             }
    6086             :             else
    6087             :             {
    6088           0 :                 CPLErrorReset();
    6089           0 :                 ret = OGRERR_NONE;
    6090             :             }
    6091             :         }
    6092         112 :         if (!x_geom)
    6093             :         {
    6094           0 :             continue;
    6095             :         }
    6096             : 
    6097             :         OGRGeometryUniquePtr x_geom_diff(
    6098             :             x_geom
    6099         112 :                 ->clone());  // this will be the geometry of the result feature
    6100         628 :         for (auto &&y : this)
    6101             :         {
    6102         516 :             OGRGeometry *y_geom = y->GetGeometryRef();
    6103         516 :             if (!y_geom)
    6104             :             {
    6105           0 :                 continue;
    6106             :             }
    6107             : 
    6108         516 :             if (x_geom_diff)
    6109             :             {
    6110         516 :                 CPLErrorReset();
    6111             :                 OGRGeometryUniquePtr x_geom_diff_new(
    6112         516 :                     x_geom_diff->Difference(y_geom));
    6113        1032 :                 if (CPLGetLastErrorType() != CE_None ||
    6114         516 :                     x_geom_diff_new == nullptr)
    6115             :                 {
    6116           0 :                     if (!bSkipFailures)
    6117             :                     {
    6118           0 :                         ret = OGRERR_FAILURE;
    6119           0 :                         goto done;
    6120             :                     }
    6121             :                     else
    6122             :                     {
    6123           0 :                         CPLErrorReset();
    6124           0 :                         ret = OGRERR_NONE;
    6125             :                     }
    6126             :                 }
    6127             :                 else
    6128             :                 {
    6129         516 :                     x_geom_diff.swap(x_geom_diff_new);
    6130             :                 }
    6131             :             }
    6132             :         }
    6133             : 
    6134         112 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    6135             :         {
    6136             :             // ok
    6137             :         }
    6138             :         else
    6139             :         {
    6140           8 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    6141           8 :             z->SetFieldsFrom(x.get(), mapMethod);
    6142           8 :             if (bPromoteToMulti)
    6143           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    6144           8 :             z->SetGeometryDirectly(x_geom_diff.release());
    6145           8 :             ret = pLayerResult->CreateFeature(z.get());
    6146           8 :             if (ret != OGRERR_NONE)
    6147             :             {
    6148           0 :                 if (!bSkipFailures)
    6149             :                 {
    6150           0 :                     goto done;
    6151             :                 }
    6152             :                 else
    6153             :                 {
    6154           0 :                     CPLErrorReset();
    6155           0 :                     ret = OGRERR_NONE;
    6156             :                 }
    6157             :             }
    6158             :         }
    6159             :     }
    6160          18 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    6161             :     {
    6162           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6163           0 :         ret = OGRERR_FAILURE;
    6164           0 :         goto done;
    6165             :     }
    6166          18 : done:
    6167             :     // release resources
    6168          18 :     SetSpatialFilter(pGeometryInputFilter);
    6169          18 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    6170          18 :     if (pGeometryMethodFilter)
    6171           0 :         delete pGeometryMethodFilter;
    6172          18 :     if (pGeometryInputFilter)
    6173           0 :         delete pGeometryInputFilter;
    6174          18 :     if (mapInput)
    6175          15 :         VSIFree(mapInput);
    6176          18 :     if (mapMethod)
    6177          14 :         VSIFree(mapMethod);
    6178          18 :     return ret;
    6179             : }
    6180             : 
    6181             : /************************************************************************/
    6182             : /*                            OGR_L_Union()                             */
    6183             : /************************************************************************/
    6184             : 
    6185             : /**
    6186             :  * \brief Union of two layers.
    6187             :  *
    6188             :  * The result layer contains features whose geometries represent areas
    6189             :  * that are in either in the input layer, in the method layer, or in
    6190             :  * both. The features in the result layer have attributes from both
    6191             :  * input and method layers. For features which represent areas that
    6192             :  * are only in the input or in the method layer the respective
    6193             :  * attributes have undefined values. The schema of the result layer
    6194             :  * can be set by the user or, if it is empty, is initialized to
    6195             :  * contain all fields in the input and method layers.
    6196             :  *
    6197             :  * \note If the schema of the result is set by user and contains
    6198             :  * fields that have the same name as a field in input and in method
    6199             :  * layer, then the attribute in the result feature will get the value
    6200             :  * from the feature of the method layer (even if it is undefined).
    6201             :  *
    6202             :  * \note For best performance use the minimum amount of features in
    6203             :  * the method layer and copy it into a memory layer.
    6204             :  *
    6205             :  * \note This method relies on GEOS support. Do not use unless the
    6206             :  * GEOS support is compiled in.
    6207             :  *
    6208             :  * The recognized list of options is :
    6209             :  * <ul>
    6210             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    6211             :  *     feature could not be inserted or a GEOS call failed.
    6212             :  * </li>
    6213             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    6214             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    6215             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    6216             :  * </li>
    6217             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    6218             :  *     will be created from the fields of the input layer.
    6219             :  * </li>
    6220             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    6221             :  *     will be created from the fields of the method layer.
    6222             :  * </li>
    6223             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    6224             :  *     geometries to pretest intersection of features of method layer
    6225             :  *     with features of this layer.
    6226             :  * </li>
    6227             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    6228             :  *     result features with lower dimension geometry that would
    6229             :  *     otherwise be added to the result layer. The default is YES, to add
    6230             :  *     features with lower dimension geometry, but only if the result layer
    6231             :  *     has an unknown geometry type.
    6232             :  * </li>
    6233             :  * </ul>
    6234             :  *
    6235             :  * This function is the same as the C++ method OGRLayer::Union().
    6236             :  *
    6237             :  * @param pLayerInput the input layer. Should not be NULL.
    6238             :  *
    6239             :  * @param pLayerMethod the method layer. Should not be NULL.
    6240             :  *
    6241             :  * @param pLayerResult the layer where the features resulting from the
    6242             :  * operation are inserted. Should not be NULL. See above the note
    6243             :  * about the schema.
    6244             :  *
    6245             :  * @param papszOptions NULL terminated list of options (may be NULL).
    6246             :  *
    6247             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    6248             :  * reporting progress or NULL.
    6249             :  *
    6250             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    6251             :  *
    6252             :  * @return an error code if there was an error or the execution was
    6253             :  * interrupted, OGRERR_NONE otherwise.
    6254             :  *
    6255             :  * @note The first geometry field is always used.
    6256             :  *
    6257             :  * @since OGR 1.10
    6258             :  */
    6259             : 
    6260           7 : OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    6261             :                    OGRLayerH pLayerResult, CSLConstList papszOptions,
    6262             :                    GDALProgressFunc pfnProgress, void *pProgressArg)
    6263             : 
    6264             : {
    6265           7 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    6266           7 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    6267           7 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    6268             : 
    6269             :     return OGRLayer::FromHandle(pLayerInput)
    6270           7 :         ->Union(OGRLayer::FromHandle(pLayerMethod),
    6271             :                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    6272           7 :                 pProgressArg);
    6273             : }
    6274             : 
    6275             : /************************************************************************/
    6276             : /*                           SymDifference()                            */
    6277             : /************************************************************************/
    6278             : 
    6279             : /**
    6280             :  * \brief Symmetrical difference of two layers.
    6281             :  *
    6282             :  * The result layer contains features whose geometries represent areas
    6283             :  * that are in either in the input layer or in the method layer but
    6284             :  * not in both. The features in the result layer have attributes from
    6285             :  * both input and method layers. For features which represent areas
    6286             :  * that are only in the input or in the method layer the respective
    6287             :  * attributes have undefined values. The schema of the result layer
    6288             :  * can be set by the user or, if it is empty, is initialized to
    6289             :  * contain all fields in the input and method layers.
    6290             :  *
    6291             :  * \note If the schema of the result is set by user and contains
    6292             :  * fields that have the same name as a field in input and in method
    6293             :  * layer, then the attribute in the result feature will get the value
    6294             :  * from the feature of the method layer (even if it is undefined).
    6295             :  *
    6296             :  * \note For best performance use the minimum amount of features in
    6297             :  * the method layer and copy it into a memory layer.
    6298             :  *
    6299             :  * \note This method relies on GEOS support. Do not use unless the
    6300             :  * GEOS support is compiled in.
    6301             :  *
    6302             :  * The recognized list of options is :
    6303             :  * <ul>
    6304             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    6305             :  *     feature could not be inserted or a GEOS call failed.
    6306             :  * </li>
    6307             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
    6308             :  *     into MultiPolygons, or LineStrings to MultiLineStrings.
    6309             :  * </li>
    6310             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    6311             :  *     will be created from the fields of the input layer.
    6312             :  * </li>
    6313             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    6314             :  *     will be created from the fields of the method layer.
    6315             :  * </li>
    6316             :  * </ul>
    6317             :  *
    6318             :  * This method is the same as the C function OGR_L_SymDifference().
    6319             :  *
    6320             :  * @param pLayerMethod the method layer. Should not be NULL.
    6321             :  *
    6322             :  * @param pLayerResult the layer where the features resulting from the
    6323             :  * operation are inserted. Should not be NULL. See above the note
    6324             :  * about the schema.
    6325             :  *
    6326             :  * @param papszOptions NULL terminated list of options (may be NULL).
    6327             :  *
    6328             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    6329             :  * reporting progress or NULL.
    6330             :  *
    6331             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    6332             :  *
    6333             :  * @return an error code if there was an error or the execution was
    6334             :  * interrupted, OGRERR_NONE otherwise.
    6335             :  *
    6336             :  * @note The first geometry field is always used.
    6337             :  *
    6338             :  * @since OGR 1.10
    6339             :  */
    6340             : 
    6341           5 : OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    6342             :                                CSLConstList papszOptions,
    6343             :                                GDALProgressFunc pfnProgress, void *pProgressArg)
    6344             : {
    6345           5 :     OGRErr ret = OGRERR_NONE;
    6346           5 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    6347           5 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    6348           5 :     OGRFeatureDefn *poDefnResult = nullptr;
    6349           5 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    6350           5 :     OGRGeometry *pGeometryInputFilter = nullptr;
    6351           5 :     int *mapInput = nullptr;
    6352           5 :     int *mapMethod = nullptr;
    6353             :     double progress_max =
    6354           5 :         static_cast<double>(GetFeatureCount(FALSE)) +
    6355           5 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    6356           5 :     double progress_counter = 0;
    6357           5 :     double progress_ticker = 0;
    6358             :     const bool bSkipFailures =
    6359           5 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    6360           5 :     const bool bPromoteToMulti = CPLTestBool(
    6361             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    6362             : 
    6363             :     // check for GEOS
    6364           5 :     if (!OGRGeometryFactory::haveGEOS())
    6365             :     {
    6366           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6367             :                  "OGRLayer::SymDifference() requires GEOS support");
    6368           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    6369             :     }
    6370             : 
    6371             :     // get resources
    6372           5 :     ret = clone_spatial_filter(this, &pGeometryInputFilter);
    6373           5 :     if (ret != OGRERR_NONE)
    6374           0 :         goto done;
    6375           5 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    6376           5 :     if (ret != OGRERR_NONE)
    6377           0 :         goto done;
    6378           5 :     ret = create_field_map(poDefnInput, &mapInput);
    6379           5 :     if (ret != OGRERR_NONE)
    6380           0 :         goto done;
    6381           5 :     ret = create_field_map(poDefnMethod, &mapMethod);
    6382           5 :     if (ret != OGRERR_NONE)
    6383           0 :         goto done;
    6384           5 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    6385             :                             mapMethod, true, papszOptions);
    6386           5 :     if (ret != OGRERR_NONE)
    6387           0 :         goto done;
    6388           5 :     poDefnResult = pLayerResult->GetLayerDefn();
    6389             : 
    6390             :     // add features based on input layer
    6391          15 :     for (auto &&x : this)
    6392             :     {
    6393             : 
    6394          10 :         if (pfnProgress)
    6395             :         {
    6396           2 :             double p = progress_counter / progress_max;
    6397           2 :             if (p > progress_ticker)
    6398             :             {
    6399           1 :                 if (!pfnProgress(p, "", pProgressArg))
    6400             :                 {
    6401           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6402           0 :                     ret = OGRERR_FAILURE;
    6403           0 :                     goto done;
    6404             :                 }
    6405             :             }
    6406           2 :             progress_counter += 1.0;
    6407             :         }
    6408             : 
    6409             :         // set up the filter on method layer
    6410          10 :         CPLErrorReset();
    6411             :         OGRGeometry *x_geom =
    6412          10 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    6413          10 :         if (CPLGetLastErrorType() != CE_None)
    6414             :         {
    6415           0 :             if (!bSkipFailures)
    6416             :             {
    6417           0 :                 ret = OGRERR_FAILURE;
    6418           0 :                 goto done;
    6419             :             }
    6420             :             else
    6421             :             {
    6422           0 :                 CPLErrorReset();
    6423           0 :                 ret = OGRERR_NONE;
    6424             :             }
    6425             :         }
    6426          10 :         if (!x_geom)
    6427             :         {
    6428           0 :             continue;
    6429             :         }
    6430             : 
    6431             :         OGRGeometryUniquePtr geom(
    6432             :             x_geom
    6433          10 :                 ->clone());  // this will be the geometry of the result feature
    6434          18 :         for (auto &&y : pLayerMethod)
    6435             :         {
    6436          11 :             OGRGeometry *y_geom = y->GetGeometryRef();
    6437          11 :             if (!y_geom)
    6438             :             {
    6439           0 :                 continue;
    6440             :             }
    6441          11 :             if (geom)
    6442             :             {
    6443          11 :                 CPLErrorReset();
    6444          11 :                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    6445          11 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    6446             :                 {
    6447           0 :                     if (!bSkipFailures)
    6448             :                     {
    6449           0 :                         ret = OGRERR_FAILURE;
    6450           0 :                         goto done;
    6451             :                     }
    6452             :                     else
    6453             :                     {
    6454           0 :                         CPLErrorReset();
    6455           0 :                         ret = OGRERR_NONE;
    6456             :                     }
    6457             :                 }
    6458             :                 else
    6459             :                 {
    6460          11 :                     geom.swap(geom_new);
    6461             :                 }
    6462             :             }
    6463          11 :             if (geom && geom->IsEmpty())
    6464           3 :                 break;
    6465             :         }
    6466             : 
    6467          10 :         if (geom && !geom->IsEmpty())
    6468             :         {
    6469           7 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    6470           7 :             z->SetFieldsFrom(x.get(), mapInput);
    6471           7 :             if (bPromoteToMulti)
    6472           2 :                 geom.reset(promote_to_multi(geom.release()));
    6473           7 :             z->SetGeometryDirectly(geom.release());
    6474           7 :             ret = pLayerResult->CreateFeature(z.get());
    6475           7 :             if (ret != OGRERR_NONE)
    6476             :             {
    6477           0 :                 if (!bSkipFailures)
    6478             :                 {
    6479           0 :                     goto done;
    6480             :                 }
    6481             :                 else
    6482             :                 {
    6483           0 :                     CPLErrorReset();
    6484           0 :                     ret = OGRERR_NONE;
    6485             :                 }
    6486             :             }
    6487             :         }
    6488             :     }
    6489             : 
    6490             :     // restore filter on method layer and add features based on it
    6491           5 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    6492          14 :     for (auto &&x : pLayerMethod)
    6493             :     {
    6494             : 
    6495           9 :         if (pfnProgress)
    6496             :         {
    6497           2 :             double p = progress_counter / progress_max;
    6498           2 :             if (p > progress_ticker)
    6499             :             {
    6500           2 :                 if (!pfnProgress(p, "", pProgressArg))
    6501             :                 {
    6502           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6503           0 :                     ret = OGRERR_FAILURE;
    6504           0 :                     goto done;
    6505             :                 }
    6506             :             }
    6507           2 :             progress_counter += 1.0;
    6508             :         }
    6509             : 
    6510             :         // set up the filter on input layer
    6511           9 :         CPLErrorReset();
    6512             :         OGRGeometry *x_geom =
    6513           9 :             set_filter_from(this, pGeometryInputFilter, x.get());
    6514           9 :         if (CPLGetLastErrorType() != CE_None)
    6515             :         {
    6516           0 :             if (!bSkipFailures)
    6517             :             {
    6518           0 :                 ret = OGRERR_FAILURE;
    6519           0 :                 goto done;
    6520             :             }
    6521             :             else
    6522             :             {
    6523           0 :                 CPLErrorReset();
    6524           0 :                 ret = OGRERR_NONE;
    6525             :             }
    6526             :         }
    6527           9 :         if (!x_geom)
    6528             :         {
    6529           0 :             continue;
    6530             :         }
    6531             : 
    6532             :         OGRGeometryUniquePtr geom(
    6533             :             x_geom
    6534           9 :                 ->clone());  // this will be the geometry of the result feature
    6535          17 :         for (auto &&y : this)
    6536             :         {
    6537          11 :             OGRGeometry *y_geom = y->GetGeometryRef();
    6538          11 :             if (!y_geom)
    6539           0 :                 continue;
    6540          11 :             if (geom)
    6541             :             {
    6542          11 :                 CPLErrorReset();
    6543          11 :                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    6544          11 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    6545             :                 {
    6546           0 :                     if (!bSkipFailures)
    6547             :                     {
    6548           0 :                         ret = OGRERR_FAILURE;
    6549           0 :                         goto done;
    6550             :                     }
    6551             :                     else
    6552             :                     {
    6553           0 :                         CPLErrorReset();
    6554           0 :                         ret = OGRERR_NONE;
    6555             :                     }
    6556             :                 }
    6557             :                 else
    6558             :                 {
    6559          11 :                     geom.swap(geom_new);
    6560             :                 }
    6561             :             }
    6562          11 :             if (geom == nullptr || geom->IsEmpty())
    6563           3 :                 break;
    6564             :         }
    6565             : 
    6566           9 :         if (geom && !geom->IsEmpty())
    6567             :         {
    6568           6 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    6569           6 :             z->SetFieldsFrom(x.get(), mapMethod);
    6570           6 :             if (bPromoteToMulti)
    6571           1 :                 geom.reset(promote_to_multi(geom.release()));
    6572           6 :             z->SetGeometryDirectly(geom.release());
    6573           6 :             ret = pLayerResult->CreateFeature(z.get());
    6574           6 :             if (ret != OGRERR_NONE)
    6575             :             {
    6576           0 :                 if (!bSkipFailures)
    6577             :                 {
    6578           0 :                     goto done;
    6579             :                 }
    6580             :                 else
    6581             :                 {
    6582           0 :                     CPLErrorReset();
    6583           0 :                     ret = OGRERR_NONE;
    6584             :                 }
    6585             :             }
    6586             :         }
    6587             :     }
    6588           5 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    6589             :     {
    6590           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6591           0 :         ret = OGRERR_FAILURE;
    6592           0 :         goto done;
    6593             :     }
    6594           5 : done:
    6595             :     // release resources
    6596           5 :     SetSpatialFilter(pGeometryInputFilter);
    6597           5 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    6598           5 :     if (pGeometryMethodFilter)
    6599           0 :         delete pGeometryMethodFilter;
    6600           5 :     if (pGeometryInputFilter)
    6601           0 :         delete pGeometryInputFilter;
    6602           5 :     if (mapInput)
    6603           4 :         VSIFree(mapInput);
    6604           5 :     if (mapMethod)
    6605           4 :         VSIFree(mapMethod);
    6606           5 :     return ret;
    6607             : }
    6608             : 
    6609             : /************************************************************************/
    6610             : /*                        OGR_L_SymDifference()                         */
    6611             : /************************************************************************/
    6612             : 
    6613             : /**
    6614             :  * \brief Symmetrical difference of two layers.
    6615             :  *
    6616             :  * The result layer contains features whose geometries represent areas
    6617             :  * that are in either in the input layer or in the method layer but
    6618             :  * not in both. The features in the result layer have attributes from
    6619             :  * both input and method layers. For features which represent areas
    6620             :  * that are only in the input or in the method layer the respective
    6621             :  * attributes have undefined values. The schema of the result layer
    6622             :  * can be set by the user or, if it is empty, is initialized to
    6623             :  * contain all fields in the input and method layers.
    6624             :  *
    6625             :  * \note If the schema of the result is set by user and contains
    6626             :  * fields that have the same name as a field in input and in method
    6627             :  * layer, then the attribute in the result feature will get the value
    6628             :  * from the feature of the method layer (even if it is undefined).
    6629             :  *
    6630             :  * \note For best performance use the minimum amount of features in
    6631             :  * the method layer and copy it into a memory layer.
    6632             :  *
    6633             :  * \note This method relies on GEOS support. Do not use unless the
    6634             :  * GEOS support is compiled in.
    6635             :  *
    6636             :  * The recognized list of options is :
    6637             :  * <ul>
    6638             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    6639             :  *     feature could not be inserted or a GEOS call failed.
    6640             :  * </li>
    6641             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    6642             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    6643             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    6644             :  * </li>
    6645             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    6646             :  *     will be created from the fields of the input layer.
    6647             :  * </li>
    6648             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    6649             :  *     will be created from the fields of the method layer.
    6650             :  * </li>
    6651             :  * </ul>
    6652             :  *
    6653             :  * This function is the same as the C++ method OGRLayer::SymDifference().
    6654             :  *
    6655             :  * @param pLayerInput the input layer. Should not be NULL.
    6656             :  *
    6657             :  * @param pLayerMethod the method layer. Should not be NULL.
    6658             :  *
    6659             :  * @param pLayerResult the layer where the features resulting from the
    6660             :  * operation are inserted. Should not be NULL. See above the note
    6661             :  * about the schema.
    6662             :  *
    6663             :  * @param papszOptions NULL terminated list of options (may be NULL).
    6664             :  *
    6665             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    6666             :  * reporting progress or NULL.
    6667             :  *
    6668             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    6669             :  *
    6670             :  * @return an error code if there was an error or the execution was
    6671             :  * interrupted, OGRERR_NONE otherwise.
    6672             :  *
    6673             :  * @note The first geometry field is always used.
    6674             :  *
    6675             :  * @since OGR 1.10
    6676             :  */
    6677             : 
    6678           4 : OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    6679             :                            OGRLayerH pLayerResult, CSLConstList papszOptions,
    6680             :                            GDALProgressFunc pfnProgress, void *pProgressArg)
    6681             : 
    6682             : {
    6683           4 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
    6684             :                       OGRERR_INVALID_HANDLE);
    6685           4 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
    6686             :                       OGRERR_INVALID_HANDLE);
    6687           4 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
    6688             :                       OGRERR_INVALID_HANDLE);
    6689             : 
    6690             :     return OGRLayer::FromHandle(pLayerInput)
    6691           4 :         ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
    6692             :                         OGRLayer::FromHandle(pLayerResult), papszOptions,
    6693           4 :                         pfnProgress, pProgressArg);
    6694             : }
    6695             : 
    6696             : /************************************************************************/
    6697             : /*                              Identity()                              */
    6698             : /************************************************************************/
    6699             : 
    6700             : /**
    6701             :  * \brief Identify the features of this layer with the ones from the
    6702             :  * identity layer.
    6703             :  *
    6704             :  * The result layer contains features whose geometries represent areas
    6705             :  * that are in the input layer. The features in the result layer have
    6706             :  * attributes from both input and method layers. The schema of the
    6707             :  * result layer can be set by the user or, if it is empty, is
    6708             :  * initialized to contain all fields in input and method layers.
    6709             :  *
    6710             :  * \note If the schema of the result is set by user and contains
    6711             :  * fields that have the same name as a field in input and in method
    6712             :  * layer, then the attribute in the result feature will get the value
    6713             :  * from the feature of the method layer (even if it is undefined).
    6714             :  *
    6715             :  * \note For best performance use the minimum amount of features in
    6716             :  * the method layer and copy it into a memory layer.
    6717             :  *
    6718             :  * \note This method relies on GEOS support. Do not use unless the
    6719             :  * GEOS support is compiled in.
    6720             :  *
    6721             :  * The recognized list of options is :
    6722             :  * <ul>
    6723             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    6724             :  *     feature could not be inserted or a GEOS call failed.
    6725             :  * </li>
    6726             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    6727             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    6728             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    6729             :  * </li>
    6730             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    6731             :  *     will be created from the fields of the input layer.
    6732             :  * </li>
    6733             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    6734             :  *     will be created from the fields of the method layer.
    6735             :  * </li>
    6736             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    6737             :  *     geometries to pretest intersection of features of method layer
    6738             :  *     with features of this layer.
    6739             :  * </li>
    6740             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    6741             :  *     result features with lower dimension geometry that would
    6742             :  *     otherwise be added to the result layer. The default is YES, to add
    6743             :  *     features with lower dimension geometry, but only if the result layer
    6744             :  *     has an unknown geometry type.
    6745             :  * </li>
    6746             :  * </ul>
    6747             :  *
    6748             :  * This method is the same as the C function OGR_L_Identity().
    6749             :  *
    6750             :  * @param pLayerMethod the method layer. Should not be NULL.
    6751             :  *
    6752             :  * @param pLayerResult the layer where the features resulting from the
    6753             :  * operation are inserted. Should not be NULL. See above the note
    6754             :  * about the schema.
    6755             :  *
    6756             :  * @param papszOptions NULL terminated list of options (may be NULL).
    6757             :  *
    6758             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    6759             :  * reporting progress or NULL.
    6760             :  *
    6761             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    6762             :  *
    6763             :  * @return an error code if there was an error or the execution was
    6764             :  * interrupted, OGRERR_NONE otherwise.
    6765             :  *
    6766             :  * @note The first geometry field is always used.
    6767             :  *
    6768             :  * @since OGR 1.10
    6769             :  */
    6770             : 
    6771           7 : OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    6772             :                           CSLConstList papszOptions,
    6773             :                           GDALProgressFunc pfnProgress, void *pProgressArg)
    6774             : {
    6775           7 :     OGRErr ret = OGRERR_NONE;
    6776           7 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    6777           7 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    6778           7 :     OGRFeatureDefn *poDefnResult = nullptr;
    6779           7 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    6780           7 :     int *mapInput = nullptr;
    6781           7 :     int *mapMethod = nullptr;
    6782           7 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    6783           7 :     double progress_counter = 0;
    6784           7 :     double progress_ticker = 0;
    6785             :     const bool bSkipFailures =
    6786           7 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    6787           7 :     const bool bPromoteToMulti = CPLTestBool(
    6788             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    6789           7 :     const bool bUsePreparedGeometries = CPLTestBool(
    6790             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    6791           7 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    6792             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    6793             : 
    6794             :     // check for GEOS
    6795           7 :     if (!OGRGeometryFactory::haveGEOS())
    6796             :     {
    6797           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6798             :                  "OGRLayer::Identity() requires GEOS support");
    6799           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    6800             :     }
    6801           7 :     if (bKeepLowerDimGeom)
    6802             :     {
    6803             :         // require that the result layer is of geom type unknown
    6804           5 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    6805             :         {
    6806           0 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    6807             :                             "since the result layer does not allow it.");
    6808           0 :             bKeepLowerDimGeom = FALSE;
    6809             :         }
    6810             :     }
    6811             : 
    6812             :     // get resources
    6813           7 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    6814           7 :     if (ret != OGRERR_NONE)
    6815           0 :         goto done;
    6816           7 :     ret = create_field_map(poDefnInput, &mapInput);
    6817           7 :     if (ret != OGRERR_NONE)
    6818           0 :         goto done;
    6819           7 :     ret = create_field_map(poDefnMethod, &mapMethod);
    6820           7 :     if (ret != OGRERR_NONE)
    6821           0 :         goto done;
    6822           7 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    6823             :                             mapMethod, true, papszOptions);
    6824           7 :     if (ret != OGRERR_NONE)
    6825           0 :         goto done;
    6826           7 :     poDefnResult = pLayerResult->GetLayerDefn();
    6827             : 
    6828             :     // split the features in input layer to the result layer
    6829          21 :     for (auto &&x : this)
    6830             :     {
    6831             : 
    6832          14 :         if (pfnProgress)
    6833             :         {
    6834           2 :             double p = progress_counter / progress_max;
    6835           2 :             if (p > progress_ticker)
    6836             :             {
    6837           1 :                 if (!pfnProgress(p, "", pProgressArg))
    6838             :                 {
    6839           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6840           0 :                     ret = OGRERR_FAILURE;
    6841           0 :                     goto done;
    6842             :                 }
    6843             :             }
    6844           2 :             progress_counter += 1.0;
    6845             :         }
    6846             : 
    6847             :         // set up the filter on method layer
    6848          14 :         CPLErrorReset();
    6849             :         OGRGeometry *x_geom =
    6850          14 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    6851          14 :         if (CPLGetLastErrorType() != CE_None)
    6852             :         {
    6853           0 :             if (!bSkipFailures)
    6854             :             {
    6855           0 :                 ret = OGRERR_FAILURE;
    6856           0 :                 goto done;
    6857             :             }
    6858             :             else
    6859             :             {
    6860           0 :                 CPLErrorReset();
    6861           0 :                 ret = OGRERR_NONE;
    6862             :             }
    6863             :         }
    6864          14 :         if (!x_geom)
    6865             :         {
    6866           0 :             continue;
    6867             :         }
    6868             : 
    6869           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    6870          14 :         if (bUsePreparedGeometries)
    6871             :         {
    6872          14 :             x_prepared_geom.reset(
    6873             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    6874          14 :             if (!x_prepared_geom)
    6875             :             {
    6876           0 :                 goto done;
    6877             :             }
    6878             :         }
    6879             : 
    6880             :         OGRGeometryUniquePtr x_geom_diff(
    6881             :             x_geom
    6882          14 :                 ->clone());  // this will be the geometry of the result feature
    6883          30 :         for (auto &&y : pLayerMethod)
    6884             :         {
    6885          16 :             OGRGeometry *y_geom = y->GetGeometryRef();
    6886          16 :             if (!y_geom)
    6887           0 :                 continue;
    6888             : 
    6889          16 :             CPLErrorReset();
    6890          32 :             if (x_prepared_geom &&
    6891          16 :                 !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
    6892          16 :                                                 OGRGeometry::ToHandle(y_geom))))
    6893             :             {
    6894           0 :                 if (CPLGetLastErrorType() == CE_None)
    6895             :                 {
    6896           0 :                     continue;
    6897             :                 }
    6898             :             }
    6899          16 :             if (CPLGetLastErrorType() != CE_None)
    6900             :             {
    6901           0 :                 if (!bSkipFailures)
    6902             :                 {
    6903           0 :                     ret = OGRERR_FAILURE;
    6904           0 :                     goto done;
    6905             :                 }
    6906             :                 else
    6907             :                 {
    6908           0 :                     CPLErrorReset();
    6909           0 :                     ret = OGRERR_NONE;
    6910             :                 }
    6911             :             }
    6912             : 
    6913          16 :             CPLErrorReset();
    6914          16 :             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
    6915          16 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    6916             :             {
    6917           0 :                 if (!bSkipFailures)
    6918             :                 {
    6919           0 :                     ret = OGRERR_FAILURE;
    6920           0 :                     goto done;
    6921             :                 }
    6922             :                 else
    6923             :                 {
    6924           0 :                     CPLErrorReset();
    6925           0 :                     ret = OGRERR_NONE;
    6926             :                 }
    6927             :             }
    6928          32 :             else if (poIntersection->IsEmpty() ||
    6929          16 :                      (!bKeepLowerDimGeom &&
    6930           6 :                       (x_geom->getDimension() == y_geom->getDimension() &&
    6931           6 :                        poIntersection->getDimension() <
    6932           6 :                            x_geom->getDimension())))
    6933             :             {
    6934             :                 /* ok*/
    6935             :             }
    6936             :             else
    6937             :             {
    6938          12 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    6939          12 :                 z->SetFieldsFrom(x.get(), mapInput);
    6940          12 :                 z->SetFieldsFrom(y.get(), mapMethod);
    6941          12 :                 if (bPromoteToMulti)
    6942           2 :                     poIntersection.reset(
    6943             :                         promote_to_multi(poIntersection.release()));
    6944          12 :                 z->SetGeometryDirectly(poIntersection.release());
    6945          12 :                 if (x_geom_diff)
    6946             :                 {
    6947          12 :                     CPLErrorReset();
    6948             :                     OGRGeometryUniquePtr x_geom_diff_new(
    6949          12 :                         x_geom_diff->Difference(y_geom));
    6950          24 :                     if (CPLGetLastErrorType() != CE_None ||
    6951          12 :                         x_geom_diff_new == nullptr)
    6952             :                     {
    6953           0 :                         if (!bSkipFailures)
    6954             :                         {
    6955           0 :                             ret = OGRERR_FAILURE;
    6956           0 :                             goto done;
    6957             :                         }
    6958             :                         else
    6959             :                         {
    6960           0 :                             CPLErrorReset();
    6961             :                         }
    6962             :                     }
    6963             :                     else
    6964             :                     {
    6965          12 :                         x_geom_diff.swap(x_geom_diff_new);
    6966             :                     }
    6967             :                 }
    6968          12 :                 ret = pLayerResult->CreateFeature(z.get());
    6969          12 :                 if (ret != OGRERR_NONE)
    6970             :                 {
    6971           0 :                     if (!bSkipFailures)
    6972             :                     {
    6973           0 :                         goto done;
    6974             :                     }
    6975             :                     else
    6976             :                     {
    6977           0 :                         CPLErrorReset();
    6978           0 :                         ret = OGRERR_NONE;
    6979             :                     }
    6980             :                 }
    6981             :             }
    6982             :         }
    6983             : 
    6984          14 :         x_prepared_geom.reset();
    6985             : 
    6986          14 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    6987             :         {
    6988             :             /* ok */
    6989             :         }
    6990             :         else
    6991             :         {
    6992          11 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    6993          11 :             z->SetFieldsFrom(x.get(), mapInput);
    6994          11 :             if (bPromoteToMulti)
    6995           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    6996          11 :             z->SetGeometryDirectly(x_geom_diff.release());
    6997          11 :             ret = pLayerResult->CreateFeature(z.get());
    6998          11 :             if (ret != OGRERR_NONE)
    6999             :             {
    7000           0 :                 if (!bSkipFailures)
    7001             :                 {
    7002           0 :                     goto done;
    7003             :                 }
    7004             :                 else
    7005             :                 {
    7006           0 :                     CPLErrorReset();
    7007           0 :                     ret = OGRERR_NONE;
    7008             :                 }
    7009             :             }
    7010             :         }
    7011             :     }
    7012           7 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    7013             :     {
    7014           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7015           0 :         ret = OGRERR_FAILURE;
    7016           0 :         goto done;
    7017             :     }
    7018           7 : done:
    7019             :     // release resources
    7020           7 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    7021           7 :     if (pGeometryMethodFilter)
    7022           0 :         delete pGeometryMethodFilter;
    7023           7 :     if (mapInput)
    7024           4 :         VSIFree(mapInput);
    7025           7 :     if (mapMethod)
    7026           4 :         VSIFree(mapMethod);
    7027           7 :     return ret;
    7028             : }
    7029             : 
    7030             : /************************************************************************/
    7031             : /*                           OGR_L_Identity()                           */
    7032             : /************************************************************************/
    7033             : 
    7034             : /**
    7035             :  * \brief Identify the features of this layer with the ones from the
    7036             :  * identity layer.
    7037             :  *
    7038             :  * The result layer contains features whose geometries represent areas
    7039             :  * that are in the input layer. The features in the result layer have
    7040             :  * attributes from both input and method layers. The schema of the
    7041             :  * result layer can be set by the user or, if it is empty, is
    7042             :  * initialized to contain all fields in input and method layers.
    7043             :  *
    7044             :  * \note If the schema of the result is set by user and contains
    7045             :  * fields that have the same name as a field in input and in method
    7046             :  * layer, then the attribute in the result feature will get the value
    7047             :  * from the feature of the method layer (even if it is undefined).
    7048             :  *
    7049             :  * \note For best performance use the minimum amount of features in
    7050             :  * the method layer and copy it into a memory layer.
    7051             :  *
    7052             :  * \note This method relies on GEOS support. Do not use unless the
    7053             :  * GEOS support is compiled in.
    7054             :  *
    7055             :  * The recognized list of options is :
    7056             :  * <ul>
    7057             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    7058             :  *     feature could not be inserted or a GEOS call failed.
    7059             :  * </li>
    7060             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    7061             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    7062             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    7063             :  * </li>
    7064             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    7065             :  *     will be created from the fields of the input layer.
    7066             :  * </li>
    7067             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    7068             :  *     will be created from the fields of the method layer.
    7069             :  * </li>
    7070             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    7071             :  *     geometries to pretest intersection of features of method layer
    7072             :  *     with features of this layer.
    7073             :  * </li>
    7074             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    7075             :  *     result features with lower dimension geometry that would
    7076             :  *     otherwise be added to the result layer. The default is YES, to add
    7077             :  *     features with lower dimension geometry, but only if the result layer
    7078             :  *     has an unknown geometry type.
    7079             :  * </li>
    7080             :  * </ul>
    7081             :  *
    7082             :  * This function is the same as the C++ method OGRLayer::Identity().
    7083             :  *
    7084             :  * @param pLayerInput the input layer. Should not be NULL.
    7085             :  *
    7086             :  * @param pLayerMethod the method layer. Should not be NULL.
    7087             :  *
    7088             :  * @param pLayerResult the layer where the features resulting from the
    7089             :  * operation are inserted. Should not be NULL. See above the note
    7090             :  * about the schema.
    7091             :  *
    7092             :  * @param papszOptions NULL terminated list of options (may be NULL).
    7093             :  *
    7094             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    7095             :  * reporting progress or NULL.
    7096             :  *
    7097             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    7098             :  *
    7099             :  * @return an error code if there was an error or the execution was
    7100             :  * interrupted, OGRERR_NONE otherwise.
    7101             :  *
    7102             :  * @note The first geometry field is always used.
    7103             :  *
    7104             :  * @since OGR 1.10
    7105             :  */
    7106             : 
    7107           6 : OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    7108             :                       OGRLayerH pLayerResult, CSLConstList papszOptions,
    7109             :                       GDALProgressFunc pfnProgress, void *pProgressArg)
    7110             : 
    7111             : {
    7112           6 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    7113           6 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    7114           6 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    7115             : 
    7116             :     return OGRLayer::FromHandle(pLayerInput)
    7117           6 :         ->Identity(OGRLayer::FromHandle(pLayerMethod),
    7118             :                    OGRLayer::FromHandle(pLayerResult), papszOptions,
    7119           6 :                    pfnProgress, pProgressArg);
    7120             : }
    7121             : 
    7122             : /************************************************************************/
    7123             : /*                               Update()                               */
    7124             : /************************************************************************/
    7125             : 
    7126             : /**
    7127             :  * \brief Update this layer with features from the update layer.
    7128             :  *
    7129             :  * The result layer contains features whose geometries represent areas
    7130             :  * that are either in the input layer or in the method layer. The
    7131             :  * features in the result layer have areas of the features of the
    7132             :  * method layer or those ares of the features of the input layer that
    7133             :  * are not covered by the method layer. The features of the result
    7134             :  * layer get their attributes from the input layer. The schema of the
    7135             :  * result layer can be set by the user or, if it is empty, is
    7136             :  * initialized to contain all fields in the input layer.
    7137             :  *
    7138             :  * \note If the schema of the result is set by user and contains
    7139             :  * fields that have the same name as a field in the method layer, then
    7140             :  * the attribute in the result feature the originates from the method
    7141             :  * layer will get the value from the feature of the method layer.
    7142             :  *
    7143             :  * \note For best performance use the minimum amount of features in
    7144             :  * the method layer and copy it into a memory layer.
    7145             :  *
    7146             :  * \note This method relies on GEOS support. Do not use unless the
    7147             :  * GEOS support is compiled in.
    7148             :  *
    7149             :  * The recognized list of options is :
    7150             :  * <ul>
    7151             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    7152             :  *     feature could not be inserted or a GEOS call failed.
    7153             :  * </li>
    7154             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    7155             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    7156             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    7157             :  * </li>
    7158             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    7159             :  *     will be created from the fields of the input layer.
    7160             :  * </li>
    7161             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    7162             :  *     will be created from the fields of the method layer.
    7163             :  * </li>
    7164             :  * </ul>
    7165             :  *
    7166             :  * This method is the same as the C function OGR_L_Update().
    7167             :  *
    7168             :  * @param pLayerMethod the method layer. Should not be NULL.
    7169             :  *
    7170             :  * @param pLayerResult the layer where the features resulting from the
    7171             :  * operation are inserted. Should not be NULL. See above the note
    7172             :  * about the schema.
    7173             :  *
    7174             :  * @param papszOptions NULL terminated list of options (may be NULL).
    7175             :  *
    7176             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    7177             :  * reporting progress or NULL.
    7178             :  *
    7179             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    7180             :  *
    7181             :  * @return an error code if there was an error or the execution was
    7182             :  * interrupted, OGRERR_NONE otherwise.
    7183             :  *
    7184             :  * @note The first geometry field is always used.
    7185             :  *
    7186             :  * @since OGR 1.10
    7187             :  */
    7188             : 
    7189           6 : OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    7190             :                         CSLConstList papszOptions, GDALProgressFunc pfnProgress,
    7191             :                         void *pProgressArg)
    7192             : {
    7193           6 :     OGRErr ret = OGRERR_NONE;
    7194           6 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    7195           6 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    7196           6 :     OGRFeatureDefn *poDefnResult = nullptr;
    7197           6 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    7198           6 :     int *mapInput = nullptr;
    7199           6 :     int *mapMethod = nullptr;
    7200             :     double progress_max =
    7201           6 :         static_cast<double>(GetFeatureCount(FALSE)) +
    7202           6 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    7203           6 :     double progress_counter = 0;
    7204           6 :     double progress_ticker = 0;
    7205             :     const bool bSkipFailures =
    7206           6 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    7207           6 :     const bool bPromoteToMulti = CPLTestBool(
    7208             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    7209             : 
    7210             :     // check for GEOS
    7211           6 :     if (!OGRGeometryFactory::haveGEOS())
    7212             :     {
    7213           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7214             :                  "OGRLayer::Update() requires GEOS support");
    7215           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    7216             :     }
    7217             : 
    7218             :     // get resources
    7219           6 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    7220           6 :     if (ret != OGRERR_NONE)
    7221           0 :         goto done;
    7222           6 :     ret = create_field_map(poDefnInput, &mapInput);
    7223           6 :     if (ret != OGRERR_NONE)
    7224           0 :         goto done;
    7225           6 :     ret = create_field_map(poDefnMethod, &mapMethod);
    7226           6 :     if (ret != OGRERR_NONE)
    7227           0 :         goto done;
    7228           6 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    7229             :                             mapMethod, false, papszOptions);
    7230           6 :     if (ret != OGRERR_NONE)
    7231           0 :         goto done;
    7232           6 :     poDefnResult = pLayerResult->GetLayerDefn();
    7233             : 
    7234             :     // add clipped features from the input layer
    7235          18 :     for (auto &&x : this)
    7236             :     {
    7237             : 
    7238          12 :         if (pfnProgress)
    7239             :         {
    7240           2 :             double p = progress_counter / progress_max;
    7241           2 :             if (p > progress_ticker)
    7242             :             {
    7243           1 :                 if (!pfnProgress(p, "", pProgressArg))
    7244             :                 {
    7245           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7246           0 :                     ret = OGRERR_FAILURE;
    7247           0 :                     goto done;
    7248             :                 }
    7249             :             }
    7250           2 :             progress_counter += 1.0;
    7251             :         }
    7252             : 
    7253             :         // set up the filter on method layer
    7254          12 :         CPLErrorReset();
    7255             :         OGRGeometry *x_geom =
    7256          12 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    7257          12 :         if (CPLGetLastErrorType() != CE_None)
    7258             :         {
    7259           0 :             if (!bSkipFailures)
    7260             :             {
    7261           0 :                 ret = OGRERR_FAILURE;
    7262           0 :                 goto done;
    7263             :             }
    7264             :             else
    7265             :             {
    7266           0 :                 CPLErrorReset();
    7267           0 :                 ret = OGRERR_NONE;
    7268             :             }
    7269             :         }
    7270          12 :         if (!x_geom)
    7271             :         {
    7272           0 :             continue;
    7273             :         }
    7274             : 
    7275             :         OGRGeometryUniquePtr x_geom_diff(
    7276          12 :             x_geom->clone());  // this will be the geometry of a result feature
    7277          28 :         for (auto &&y : pLayerMethod)
    7278             :         {
    7279          16 :             OGRGeometry *y_geom = y->GetGeometryRef();
    7280          16 :             if (!y_geom)
    7281           0 :                 continue;
    7282          16 :             if (x_geom_diff)
    7283             :             {
    7284          16 :                 CPLErrorReset();
    7285             :                 OGRGeometryUniquePtr x_geom_diff_new(
    7286          16 :                     x_geom_diff->Difference(y_geom));
    7287          32 :                 if (CPLGetLastErrorType() != CE_None ||
    7288          16 :                     x_geom_diff_new == nullptr)
    7289             :                 {
    7290           0 :                     if (!bSkipFailures)
    7291             :                     {
    7292           0 :                         ret = OGRERR_FAILURE;
    7293           0 :                         goto done;
    7294             :                     }
    7295             :                     else
    7296             :                     {
    7297           0 :                         CPLErrorReset();
    7298           0 :                         ret = OGRERR_NONE;
    7299             :                     }
    7300             :                 }
    7301             :                 else
    7302             :                 {
    7303          16 :                     x_geom_diff.swap(x_geom_diff_new);
    7304             :                 }
    7305             :             }
    7306             :         }
    7307             : 
    7308          12 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    7309             :         {
    7310             :             /* ok */
    7311             :         }
    7312             :         else
    7313             :         {
    7314           7 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    7315           7 :             z->SetFieldsFrom(x.get(), mapInput);
    7316           7 :             if (bPromoteToMulti)
    7317           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    7318           7 :             z->SetGeometryDirectly(x_geom_diff.release());
    7319           7 :             ret = pLayerResult->CreateFeature(z.get());
    7320           7 :             if (ret != OGRERR_NONE)
    7321             :             {
    7322           0 :                 if (!bSkipFailures)
    7323             :                 {
    7324           0 :                     goto done;
    7325             :                 }
    7326             :                 else
    7327             :                 {
    7328           0 :                     CPLErrorReset();
    7329           0 :                     ret = OGRERR_NONE;
    7330             :                 }
    7331             :             }
    7332             :         }
    7333             :     }
    7334             : 
    7335             :     // restore the original filter and add features from the update layer
    7336           6 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    7337          16 :     for (auto &&y : pLayerMethod)
    7338             :     {
    7339             : 
    7340          10 :         if (pfnProgress)
    7341             :         {
    7342           1 :             double p = progress_counter / progress_max;
    7343           1 :             if (p > progress_ticker)
    7344             :             {
    7345           1 :                 if (!pfnProgress(p, "", pProgressArg))
    7346             :                 {
    7347           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7348           0 :                     ret = OGRERR_FAILURE;
    7349           0 :                     goto done;
    7350             :                 }
    7351             :             }
    7352           1 :             progress_counter += 1.0;
    7353             :         }
    7354             : 
    7355          10 :         OGRGeometry *y_geom = y->StealGeometry();
    7356          10 :         if (!y_geom)
    7357           0 :             continue;
    7358          10 :         OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    7359          10 :         if (mapMethod)
    7360           6 :             z->SetFieldsFrom(y.get(), mapMethod);
    7361          10 :         z->SetGeometryDirectly(y_geom);
    7362          10 :         ret = pLayerResult->CreateFeature(z.get());
    7363          10 :         if (ret != OGRERR_NONE)
    7364             :         {
    7365           0 :             if (!bSkipFailures)
    7366             :             {
    7367           0 :                 goto done;
    7368             :             }
    7369             :             else
    7370             :             {
    7371           0 :                 CPLErrorReset();
    7372           0 :                 ret = OGRERR_NONE;
    7373             :             }
    7374             :         }
    7375             :     }
    7376           6 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    7377             :     {
    7378           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7379           0 :         ret = OGRERR_FAILURE;
    7380           0 :         goto done;
    7381             :     }
    7382           6 : done:
    7383             :     // release resources
    7384           6 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    7385           6 :     if (pGeometryMethodFilter)
    7386           0 :         delete pGeometryMethodFilter;
    7387           6 :     if (mapInput)
    7388           4 :         VSIFree(mapInput);
    7389           6 :     if (mapMethod)
    7390           4 :         VSIFree(mapMethod);
    7391           6 :     return ret;
    7392             : }
    7393             : 
    7394             : /************************************************************************/
    7395             : /*                            OGR_L_Update()                            */
    7396             : /************************************************************************/
    7397             : 
    7398             : /**
    7399             :  * \brief Update this layer with features from the update layer.
    7400             :  *
    7401             :  * The result layer contains features whose geometries represent areas
    7402             :  * that are either in the input layer or in the method layer. The
    7403             :  * features in the result layer have areas of the features of the
    7404             :  * method layer or those ares of the features of the input layer that
    7405             :  * are not covered by the method layer. The features of the result
    7406             :  * layer get their attributes from the input layer. The schema of the
    7407             :  * result layer can be set by the user or, if it is empty, is
    7408             :  * initialized to contain all fields in the input layer.
    7409             :  *
    7410             :  * \note If the schema of the result is set by user and contains
    7411             :  * fields that have the same name as a field in the method layer, then
    7412             :  * the attribute in the result feature the originates from the method
    7413             :  * layer will get the value from the feature of the method layer.
    7414             :  *
    7415             :  * \note For best performance use the minimum amount of features in
    7416             :  * the method layer and copy it into a memory layer.
    7417             :  *
    7418             :  * \note This method relies on GEOS support. Do not use unless the
    7419             :  * GEOS support is compiled in.
    7420             :  *
    7421             :  * The recognized list of options is :
    7422             :  * <ul>
    7423             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    7424             :  *     feature could not be inserted or a GEOS call failed.
    7425             :  * </li>
    7426             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    7427             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    7428             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    7429             :  * </li>
    7430             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    7431             :  *     will be created from the fields of the input layer.
    7432             :  * </li>
    7433             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    7434             :  *     will be created from the fields of the method layer.
    7435             :  * </li>
    7436             :  * </ul>
    7437             :  *
    7438             :  * This function is the same as the C++ method OGRLayer::Update().
    7439             :  *
    7440             :  * @param pLayerInput the input layer. Should not be NULL.
    7441             :  *
    7442             :  * @param pLayerMethod the method layer. Should not be NULL.
    7443             :  *
    7444             :  * @param pLayerResult the layer where the features resulting from the
    7445             :  * operation are inserted. Should not be NULL. See above the note
    7446             :  * about the schema.
    7447             :  *
    7448             :  * @param papszOptions NULL terminated list of options (may be NULL).
    7449             :  *
    7450             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    7451             :  * reporting progress or NULL.
    7452             :  *
    7453             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    7454             :  *
    7455             :  * @return an error code if there was an error or the execution was
    7456             :  * interrupted, OGRERR_NONE otherwise.
    7457             :  *
    7458             :  * @note The first geometry field is always used.
    7459             :  *
    7460             :  * @since OGR 1.10
    7461             :  */
    7462             : 
    7463           5 : OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    7464             :                     OGRLayerH pLayerResult, CSLConstList papszOptions,
    7465             :                     GDALProgressFunc pfnProgress, void *pProgressArg)
    7466             : 
    7467             : {
    7468           5 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    7469           5 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    7470           5 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    7471             : 
    7472             :     return OGRLayer::FromHandle(pLayerInput)
    7473           5 :         ->Update(OGRLayer::FromHandle(pLayerMethod),
    7474             :                  OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    7475           5 :                  pProgressArg);
    7476             : }
    7477             : 
    7478             : /************************************************************************/
    7479             : /*                                Clip()                                */
    7480             : /************************************************************************/
    7481             : 
    7482             : /**
    7483             :  * \brief Clip off areas that are not covered by the method layer.
    7484             :  *
    7485             :  * The result layer contains features whose geometries represent areas
    7486             :  * that are in the input layer and in the method layer. The features
    7487             :  * in the result layer have the (possibly clipped) areas of features
    7488             :  * in the input layer and the attributes from the same features. The
    7489             :  * schema of the result layer can be set by the user or, if it is
    7490             :  * empty, is initialized to contain all fields in the input layer.
    7491             :  *
    7492             :  * \note For best performance use the minimum amount of features in
    7493             :  * the method layer and copy it into a memory layer.
    7494             :  *
    7495             :  * \note This method relies on GEOS support. Do not use unless the
    7496             :  * GEOS support is compiled in.
    7497             :  *
    7498             :  * The recognized list of options is :
    7499             :  * <ul>
    7500             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    7501             :  *     feature could not be inserted or a GEOS call failed.
    7502             :  * </li>
    7503             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    7504             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    7505             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    7506             :  * </li>
    7507             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    7508             :  *     will be created from the fields of the input layer.
    7509             :  * </li>
    7510             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    7511             :  *     will be created from the fields of the method layer.
    7512             :  * </li>
    7513             :  * </ul>
    7514             :  *
    7515             :  * This method is the same as the C function OGR_L_Clip().
    7516             :  *
    7517             :  * @param pLayerMethod the method layer. Should not be NULL.
    7518             :  *
    7519             :  * @param pLayerResult the layer where the features resulting from the
    7520             :  * operation are inserted. Should not be NULL. See above the note
    7521             :  * about the schema.
    7522             :  *
    7523             :  * @param papszOptions NULL terminated list of options (may be NULL).
    7524             :  *
    7525             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    7526             :  * reporting progress or NULL.
    7527             :  *
    7528             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    7529             :  *
    7530             :  * @return an error code if there was an error or the execution was
    7531             :  * interrupted, OGRERR_NONE otherwise.
    7532             :  *
    7533             :  * @note The first geometry field is always used.
    7534             :  *
    7535             :  * @since OGR 1.10
    7536             :  */
    7537             : 
    7538           4 : OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    7539             :                       CSLConstList papszOptions, GDALProgressFunc pfnProgress,
    7540             :                       void *pProgressArg)
    7541             : {
    7542           4 :     OGRErr ret = OGRERR_NONE;
    7543           4 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    7544           4 :     OGRFeatureDefn *poDefnResult = nullptr;
    7545           4 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    7546           4 :     int *mapInput = nullptr;
    7547           4 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    7548           4 :     double progress_counter = 0;
    7549           4 :     double progress_ticker = 0;
    7550             :     const bool bSkipFailures =
    7551           4 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    7552           4 :     const bool bPromoteToMulti = CPLTestBool(
    7553             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    7554             : 
    7555             :     // check for GEOS
    7556           4 :     if (!OGRGeometryFactory::haveGEOS())
    7557             :     {
    7558           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7559             :                  "OGRLayer::Clip() requires GEOS support");
    7560           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    7561             :     }
    7562             : 
    7563           4 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    7564           4 :     if (ret != OGRERR_NONE)
    7565           0 :         goto done;
    7566           4 :     ret = create_field_map(poDefnInput, &mapInput);
    7567           4 :     if (ret != OGRERR_NONE)
    7568           0 :         goto done;
    7569           4 :     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
    7570             :                             nullptr, false, papszOptions);
    7571           4 :     if (ret != OGRERR_NONE)
    7572           0 :         goto done;
    7573             : 
    7574           4 :     poDefnResult = pLayerResult->GetLayerDefn();
    7575          12 :     for (auto &&x : this)
    7576             :     {
    7577             : 
    7578           8 :         if (pfnProgress)
    7579             :         {
    7580           2 :             double p = progress_counter / progress_max;
    7581           2 :             if (p > progress_ticker)
    7582             :             {
    7583           1 :                 if (!pfnProgress(p, "", pProgressArg))
    7584             :                 {
    7585           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7586           0 :                     ret = OGRERR_FAILURE;
    7587           0 :                     goto done;
    7588             :                 }
    7589             :             }
    7590           2 :             progress_counter += 1.0;
    7591             :         }
    7592             : 
    7593             :         // set up the filter on method layer
    7594           8 :         CPLErrorReset();
    7595             :         OGRGeometry *x_geom =
    7596           8 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    7597           8 :         if (CPLGetLastErrorType() != CE_None)
    7598             :         {
    7599           0 :             if (!bSkipFailures)
    7600             :             {
    7601           0 :                 ret = OGRERR_FAILURE;
    7602           0 :                 goto done;
    7603             :             }
    7604             :             else
    7605             :             {
    7606           0 :                 CPLErrorReset();
    7607           0 :                 ret = OGRERR_NONE;
    7608             :             }
    7609             :         }
    7610           8 :         if (!x_geom)
    7611             :         {
    7612           0 :             continue;
    7613             :         }
    7614             : 
    7615             :         OGRGeometryUniquePtr
    7616           0 :             geom;  // this will be the geometry of the result feature
    7617             :         // incrementally add area from y to geom
    7618          16 :         for (auto &&y : pLayerMethod)
    7619             :         {
    7620           8 :             OGRGeometry *y_geom = y->GetGeometryRef();
    7621           8 :             if (!y_geom)
    7622           0 :                 continue;
    7623           8 :             if (!geom)
    7624             :             {
    7625           8 :                 geom.reset(y_geom->clone());
    7626             :             }
    7627             :             else
    7628             :             {
    7629           0 :                 CPLErrorReset();
    7630           0 :                 OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
    7631           0 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    7632             :                 {
    7633           0 :                     if (!bSkipFailures)
    7634             :                     {
    7635           0 :                         ret = OGRERR_FAILURE;
    7636           0 :                         goto done;
    7637             :                     }
    7638             :                     else
    7639             :                     {
    7640           0 :                         CPLErrorReset();
    7641           0 :                         ret = OGRERR_NONE;
    7642             :                     }
    7643             :                 }
    7644             :                 else
    7645             :                 {
    7646           0 :                     geom.swap(geom_new);
    7647             :                 }
    7648             :             }
    7649             :         }
    7650             : 
    7651             :         // possibly add a new feature with area x intersection sum of y
    7652           8 :         if (geom)
    7653             :         {
    7654           8 :             CPLErrorReset();
    7655             :             OGRGeometryUniquePtr poIntersection(
    7656           8 :                 x_geom->Intersection(geom.get()));
    7657           8 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    7658             :             {
    7659           0 :                 if (!bSkipFailures)
    7660             :                 {
    7661           0 :                     ret = OGRERR_FAILURE;
    7662           0 :                     goto done;
    7663             :                 }
    7664             :                 else
    7665             :                 {
    7666           0 :                     CPLErrorReset();
    7667           0 :                     ret = OGRERR_NONE;
    7668             :                 }
    7669             :             }
    7670           8 :             else if (!poIntersection->IsEmpty())
    7671             :             {
    7672           8 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    7673           8 :                 z->SetFieldsFrom(x.get(), mapInput);
    7674           8 :                 if (bPromoteToMulti)
    7675           2 :                     poIntersection.reset(
    7676             :                         promote_to_multi(poIntersection.release()));
    7677           8 :                 z->SetGeometryDirectly(poIntersection.release());
    7678           8 :                 ret = pLayerResult->CreateFeature(z.get());
    7679           8 :                 if (ret != OGRERR_NONE)
    7680             :                 {
    7681           0 :                     if (!bSkipFailures)
    7682             :                     {
    7683           0 :                         goto done;
    7684             :                     }
    7685             :                     else
    7686             :                     {
    7687           0 :                         CPLErrorReset();
    7688           0 :                         ret = OGRERR_NONE;
    7689             :                     }
    7690             :                 }
    7691             :             }
    7692             :         }
    7693             :     }
    7694           4 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    7695             :     {
    7696           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7697           0 :         ret = OGRERR_FAILURE;
    7698           0 :         goto done;
    7699             :     }
    7700           4 : done:
    7701             :     // release resources
    7702           4 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    7703           4 :     if (pGeometryMethodFilter)
    7704           0 :         delete pGeometryMethodFilter;
    7705           4 :     if (mapInput)
    7706           4 :         VSIFree(mapInput);
    7707           4 :     return ret;
    7708             : }
    7709             : 
    7710             : /************************************************************************/
    7711             : /*                             OGR_L_Clip()                             */
    7712             : /************************************************************************/
    7713             : 
    7714             : /**
    7715             :  * \brief Clip off areas that are not covered by the method layer.
    7716             :  *
    7717             :  * The result layer contains features whose geometries represent areas
    7718             :  * that are in the input layer and in the method layer. The features
    7719             :  * in the result layer have the (possibly clipped) areas of features
    7720             :  * in the input layer and the attributes from the same features. The
    7721             :  * schema of the result layer can be set by the user or, if it is
    7722             :  * empty, is initialized to contain all fields in the input layer.
    7723             :  *
    7724             :  * \note For best performance use the minimum amount of features in
    7725             :  * the method layer and copy it into a memory layer.
    7726             :  *
    7727             :  * \note This method relies on GEOS support. Do not use unless the
    7728             :  * GEOS support is compiled in.
    7729             :  *
    7730             :  * The recognized list of options is :
    7731             :  * <ul>
    7732             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    7733             :  *     feature could not be inserted or a GEOS call failed.
    7734             :  * </li>
    7735             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    7736             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    7737             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    7738             :  * </li>
    7739             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    7740             :  *     will be created from the fields of the input layer.
    7741             :  * </li>
    7742             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    7743             :  *     will be created from the fields of the method layer.
    7744             :  * </li>
    7745             :  * </ul>
    7746             :  *
    7747             :  * This function is the same as the C++ method OGRLayer::Clip().
    7748             :  *
    7749             :  * @param pLayerInput the input layer. Should not be NULL.
    7750             :  *
    7751             :  * @param pLayerMethod the method layer. Should not be NULL.
    7752             :  *
    7753             :  * @param pLayerResult the layer where the features resulting from the
    7754             :  * operation are inserted. Should not be NULL. See above the note
    7755             :  * about the schema.
    7756             :  *
    7757             :  * @param papszOptions NULL terminated list of options (may be NULL).
    7758             :  *
    7759             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    7760             :  * reporting progress or NULL.
    7761             :  *
    7762             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    7763             :  *
    7764             :  * @return an error code if there was an error or the execution was
    7765             :  * interrupted, OGRERR_NONE otherwise.
    7766             :  *
    7767             :  * @note The first geometry field is always used.
    7768             :  *
    7769             :  * @since OGR 1.10
    7770             :  */
    7771             : 
    7772           3 : OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    7773             :                   OGRLayerH pLayerResult, CSLConstList papszOptions,
    7774             :                   GDALProgressFunc pfnProgress, void *pProgressArg)
    7775             : 
    7776             : {
    7777           3 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    7778           3 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    7779           3 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    7780             : 
    7781             :     return OGRLayer::FromHandle(pLayerInput)
    7782           3 :         ->Clip(OGRLayer::FromHandle(pLayerMethod),
    7783             :                OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    7784           3 :                pProgressArg);
    7785             : }
    7786             : 
    7787             : /************************************************************************/
    7788             : /*                               Erase()                                */
    7789             : /************************************************************************/
    7790             : 
    7791             : /**
    7792             :  * \brief Remove areas that are covered by the method layer.
    7793             :  *
    7794             :  * The result layer contains features whose geometries represent areas
    7795             :  * that are in the input layer but not in the method layer. The
    7796             :  * features in the result layer have attributes from the input
    7797             :  * layer. The schema of the result layer can be set by the user or, if
    7798             :  * it is empty, is initialized to contain all fields in the input
    7799             :  * layer.
    7800             :  *
    7801             :  * \note For best performance use the minimum amount of features in
    7802             :  * the method layer and copy it into a memory layer.
    7803             :  *
    7804             :  * \note This method relies on GEOS support. Do not use unless the
    7805             :  * GEOS support is compiled in.
    7806             :  *
    7807             :  * The recognized list of options is :
    7808             :  * <ul>
    7809             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    7810             :  *     feature could not be inserted or a GEOS call failed.
    7811             :  * </li>
    7812             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    7813             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    7814             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    7815             :  * </li>
    7816             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    7817             :  *     will be created from the fields of the input layer.
    7818             :  * </li>
    7819             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    7820             :  *     will be created from the fields of the method layer.
    7821             :  * </li>
    7822             :  * </ul>
    7823             :  *
    7824             :  * This method is the same as the C function OGR_L_Erase().
    7825             :  *
    7826             :  * @param pLayerMethod the method layer. Should not be NULL.
    7827             :  *
    7828             :  * @param pLayerResult the layer where the features resulting from the
    7829             :  * operation are inserted. Should not be NULL. See above the note
    7830             :  * about the schema.
    7831             :  *
    7832             :  * @param papszOptions NULL terminated list of options (may be NULL).
    7833             :  *
    7834             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    7835             :  * reporting progress or NULL.
    7836             :  *
    7837             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    7838             :  *
    7839             :  * @return an error code if there was an error or the execution was
    7840             :  * interrupted, OGRERR_NONE otherwise.
    7841             :  *
    7842             :  * @note The first geometry field is always used.
    7843             :  *
    7844             :  * @since OGR 1.10
    7845             :  */
    7846             : 
    7847           7 : OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    7848             :                        CSLConstList papszOptions, GDALProgressFunc pfnProgress,
    7849             :                        void *pProgressArg)
    7850             : {
    7851           7 :     OGRErr ret = OGRERR_NONE;
    7852           7 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    7853           7 :     OGRFeatureDefn *poDefnResult = nullptr;
    7854           7 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    7855           7 :     int *mapInput = nullptr;
    7856           7 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    7857           7 :     double progress_counter = 0;
    7858           7 :     double progress_ticker = 0;
    7859             :     const bool bSkipFailures =
    7860           7 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    7861           7 :     const bool bPromoteToMulti = CPLTestBool(
    7862             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    7863             : 
    7864             :     // check for GEOS
    7865           7 :     if (!OGRGeometryFactory::haveGEOS())
    7866             :     {
    7867           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7868             :                  "OGRLayer::Erase() requires GEOS support");
    7869           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    7870             :     }
    7871             : 
    7872             :     // get resources
    7873           7 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    7874           7 :     if (ret != OGRERR_NONE)
    7875           0 :         goto done;
    7876           7 :     ret = create_field_map(poDefnInput, &mapInput);
    7877           7 :     if (ret != OGRERR_NONE)
    7878           0 :         goto done;
    7879           7 :     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
    7880             :                             nullptr, false, papszOptions);
    7881           7 :     if (ret != OGRERR_NONE)
    7882           0 :         goto done;
    7883           7 :     poDefnResult = pLayerResult->GetLayerDefn();
    7884             : 
    7885          21 :     for (auto &&x : this)
    7886             :     {
    7887             : 
    7888          14 :         if (pfnProgress)
    7889             :         {
    7890           2 :             double p = progress_counter / progress_max;
    7891           2 :             if (p > progress_ticker)
    7892             :             {
    7893           1 :                 if (!pfnProgress(p, "", pProgressArg))
    7894             :                 {
    7895           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7896           0 :                     ret = OGRERR_FAILURE;
    7897           0 :                     goto done;
    7898             :                 }
    7899             :             }
    7900           2 :             progress_counter += 1.0;
    7901             :         }
    7902             : 
    7903             :         // set up the filter on the method layer
    7904          14 :         CPLErrorReset();
    7905             :         OGRGeometry *x_geom =
    7906          14 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    7907          14 :         if (CPLGetLastErrorType() != CE_None)
    7908             :         {
    7909           0 :             if (!bSkipFailures)
    7910             :             {
    7911           0 :                 ret = OGRERR_FAILURE;
    7912           0 :                 goto done;
    7913             :             }
    7914             :             else
    7915             :             {
    7916           0 :                 CPLErrorReset();
    7917           0 :                 ret = OGRERR_NONE;
    7918             :             }
    7919             :         }
    7920          14 :         if (!x_geom)
    7921             :         {
    7922           0 :             continue;
    7923             :         }
    7924             : 
    7925             :         OGRGeometryUniquePtr geom(
    7926             :             x_geom
    7927          14 :                 ->clone());  // this will be the geometry of the result feature
    7928             :         // incrementally erase y from geom
    7929          22 :         for (auto &&y : pLayerMethod)
    7930             :         {
    7931          11 :             OGRGeometry *y_geom = y->GetGeometryRef();
    7932          11 :             if (!y_geom)
    7933           0 :                 continue;
    7934          11 :             CPLErrorReset();
    7935          11 :             OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    7936          11 :             if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    7937             :             {
    7938           0 :                 if (!bSkipFailures)
    7939             :                 {
    7940           0 :                     ret = OGRERR_FAILURE;
    7941           0 :                     goto done;
    7942             :                 }
    7943             :                 else
    7944             :                 {
    7945           0 :                     CPLErrorReset();
    7946           0 :                     ret = OGRERR_NONE;
    7947             :                 }
    7948             :             }
    7949             :             else
    7950             :             {
    7951          11 :                 geom.swap(geom_new);
    7952          11 :                 if (geom->IsEmpty())
    7953             :                 {
    7954           3 :                     break;
    7955             :                 }
    7956             :             }
    7957             :         }
    7958             : 
    7959             :         // add a new feature if there is remaining area
    7960          14 :         if (!geom->IsEmpty())
    7961             :         {
    7962          11 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    7963          11 :             z->SetFieldsFrom(x.get(), mapInput);
    7964          11 :             if (bPromoteToMulti)
    7965           4 :                 geom.reset(promote_to_multi(geom.release()));
    7966          11 :             z->SetGeometryDirectly(geom.release());
    7967          11 :             ret = pLayerResult->CreateFeature(z.get());
    7968          11 :             if (ret != OGRERR_NONE)
    7969             :             {
    7970           0 :                 if (!bSkipFailures)
    7971             :                 {
    7972           0 :                     goto done;
    7973             :                 }
    7974             :                 else
    7975             :                 {
    7976           0 :                     CPLErrorReset();
    7977           0 :                     ret = OGRERR_NONE;
    7978             :                 }
    7979             :             }
    7980             :         }
    7981             :     }
    7982           7 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    7983             :     {
    7984           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7985           0 :         ret = OGRERR_FAILURE;
    7986           0 :         goto done;
    7987             :     }
    7988           7 : done:
    7989             :     // release resources
    7990           7 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    7991           7 :     if (pGeometryMethodFilter)
    7992           0 :         delete pGeometryMethodFilter;
    7993           7 :     if (mapInput)
    7994           6 :         VSIFree(mapInput);
    7995           7 :     return ret;
    7996             : }
    7997             : 
    7998             : /************************************************************************/
    7999             : /*                            OGR_L_Erase()                             */
    8000             : /************************************************************************/
    8001             : 
    8002             : /**
    8003             :  * \brief Remove areas that are covered by the method layer.
    8004             :  *
    8005             :  * The result layer contains features whose geometries represent areas
    8006             :  * that are in the input layer but not in the method layer. The
    8007             :  * features in the result layer have attributes from the input
    8008             :  * layer. The schema of the result layer can be set by the user or, if
    8009             :  * it is empty, is initialized to contain all fields in the input
    8010             :  * layer.
    8011             :  *
    8012             :  * \note For best performance use the minimum amount of features in
    8013             :  * the method layer and copy it into a memory layer.
    8014             :  *
    8015             :  * \note This method relies on GEOS support. Do not use unless the
    8016             :  * GEOS support is compiled in.
    8017             :  *
    8018             :  * The recognized list of options is :
    8019             :  * <ul>
    8020             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    8021             :  *     feature could not be inserted or a GEOS call failed.
    8022             :  * </li>
    8023             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    8024             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    8025             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    8026             :  * </li>
    8027             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    8028             :  *     will be created from the fields of the input layer.
    8029             :  * </li>
    8030             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    8031             :  *     will be created from the fields of the method layer.
    8032             :  * </li>
    8033             :  * </ul>
    8034             :  *
    8035             :  * This function is the same as the C++ method OGRLayer::Erase().
    8036             :  *
    8037             :  * @param pLayerInput the input layer. Should not be NULL.
    8038             :  *
    8039             :  * @param pLayerMethod the method layer. Should not be NULL.
    8040             :  *
    8041             :  * @param pLayerResult the layer where the features resulting from the
    8042             :  * operation are inserted. Should not be NULL. See above the note
    8043             :  * about the schema.
    8044             :  *
    8045             :  * @param papszOptions NULL terminated list of options (may be NULL).
    8046             :  *
    8047             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    8048             :  * reporting progress or NULL.
    8049             :  *
    8050             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    8051             :  *
    8052             :  * @return an error code if there was an error or the execution was
    8053             :  * interrupted, OGRERR_NONE otherwise.
    8054             :  *
    8055             :  * @note The first geometry field is always used.
    8056             :  *
    8057             :  * @since OGR 1.10
    8058             :  */
    8059             : 
    8060           6 : OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    8061             :                    OGRLayerH pLayerResult, CSLConstList papszOptions,
    8062             :                    GDALProgressFunc pfnProgress, void *pProgressArg)
    8063             : 
    8064             : {
    8065           6 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    8066           6 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    8067           6 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    8068             : 
    8069             :     return OGRLayer::FromHandle(pLayerInput)
    8070           6 :         ->Erase(OGRLayer::FromHandle(pLayerMethod),
    8071             :                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    8072           6 :                 pProgressArg);
    8073             : }
    8074             : 
    8075             : /************************************************************************/
    8076             : /*                  OGRLayer::FeatureIterator::Private                  */
    8077             : /************************************************************************/
    8078             : 
    8079             : struct OGRLayer::FeatureIterator::Private
    8080             : {
    8081             :     CPL_DISALLOW_COPY_ASSIGN(Private)
    8082       40154 :     Private() = default;
    8083             : 
    8084             :     OGRFeatureUniquePtr m_poFeature{};
    8085             :     OGRLayer *m_poLayer = nullptr;
    8086             :     bool m_bError = false;
    8087             :     bool m_bEOF = true;
    8088             : };
    8089             : 
    8090             : /************************************************************************/
    8091             : /*             OGRLayer::FeatureIterator::FeatureIterator()             */
    8092             : /************************************************************************/
    8093             : 
    8094       40154 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
    8095       40154 :     : m_poPrivate(new OGRLayer::FeatureIterator::Private())
    8096             : {
    8097       40154 :     m_poPrivate->m_poLayer = poLayer;
    8098       40154 :     if (bStart)
    8099             :     {
    8100       20077 :         if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
    8101             :         {
    8102           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    8103             :                      "Only one feature iterator can be "
    8104             :                      "active at a time");
    8105           1 :             m_poPrivate->m_bError = true;
    8106             :         }
    8107             :         else
    8108             :         {
    8109       20076 :             m_poPrivate->m_poLayer->ResetReading();
    8110       40152 :             m_poPrivate->m_poFeature.reset(
    8111       20076 :                 m_poPrivate->m_poLayer->GetNextFeature());
    8112       20076 :             m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
    8113       20076 :             m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
    8114             :         }
    8115             :     }
    8116       40154 : }
    8117             : 
    8118             : /************************************************************************/
    8119             : /*            ~OGRLayer::FeatureIterator::FeatureIterator()             */
    8120             : /************************************************************************/
    8121             : 
    8122       40154 : OGRLayer::FeatureIterator::~FeatureIterator()
    8123             : {
    8124       40154 :     if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
    8125       40153 :         m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
    8126       40154 : }
    8127             : 
    8128             : /************************************************************************/
    8129             : /*                             operator*()                              */
    8130             : /************************************************************************/
    8131             : 
    8132      169687 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
    8133             : {
    8134      169687 :     return m_poPrivate->m_poFeature;
    8135             : }
    8136             : 
    8137             : /************************************************************************/
    8138             : /*                             operator++()                             */
    8139             : /************************************************************************/
    8140             : 
    8141      168930 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
    8142             : {
    8143      168930 :     m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
    8144      168930 :     m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
    8145      168930 :     return *this;
    8146             : }
    8147             : 
    8148             : /************************************************************************/
    8149             : /*                             operator!=()                             */
    8150             : /************************************************************************/
    8151             : 
    8152      189007 : bool OGRLayer::FeatureIterator::operator!=(
    8153             :     const OGRLayer::FeatureIterator &it) const
    8154             : {
    8155      189007 :     return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
    8156             : }
    8157             : 
    8158             : /************************************************************************/
    8159             : /*                               begin()                                */
    8160             : /************************************************************************/
    8161             : 
    8162       20077 : OGRLayer::FeatureIterator OGRLayer::begin()
    8163             : {
    8164       20077 :     return {this, true};
    8165             : }
    8166             : 
    8167             : /************************************************************************/
    8168             : /*                                end()                                 */
    8169             : /************************************************************************/
    8170             : 
    8171       20077 : OGRLayer::FeatureIterator OGRLayer::end()
    8172             : {
    8173       20077 :     return {this, false};
    8174             : }
    8175             : 
    8176             : /************************************************************************/
    8177             : /*                     OGRLayer::GetGeometryTypes()                     */
    8178             : /************************************************************************/
    8179             : 
    8180             : /** \brief Get actual geometry types found in features.
    8181             :  *
    8182             :  * This method iterates over features to retrieve their geometry types. This
    8183             :  * is mostly useful for layers that report a wkbUnknown geometry type with
    8184             :  * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
    8185             :  *
    8186             :  * By default this method returns an array of nEntryCount entries with each
    8187             :  * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
    8188             :  * number of features (in OGRGeometryTypeCounter::nCount).
    8189             :  * Features without geometries are reported as eGeomType == wkbNone.
    8190             :  *
    8191             :  * The nFlagsGGT parameter can be a combination (with binary or operator) of the
    8192             :  * following hints:
    8193             :  * <ul>
    8194             :  * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
    8195             :  * matter, not the number of features per geometry type. Consequently the value
    8196             :  * of OGRGeometryTypeCounter::nCount should be ignored.</li>
    8197             :  * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
    8198             :  * iterating over features as soon as 2 different geometry types (not counting
    8199             :  * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
    8200             :  * should be ignored (zero might be systematically reported by some
    8201             :  * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
    8202             :  * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
    8203             :  * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
    8204             :  * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
    8205             :  * geometries.</li>
    8206             :  * </ul>
    8207             :  *
    8208             :  * If the layer has no features, a non-NULL returned array with nEntryCount == 0
    8209             :  * will be returned.
    8210             :  *
    8211             :  * Spatial and/or attribute filters will be taken into account.
    8212             :  *
    8213             :  * This method will error out on a layer without geometry fields
    8214             :  * (GetGeomType() == wkbNone).
    8215             :  *
    8216             :  * A cancellation callback may be provided. The progress percentage it is called
    8217             :  * with is not relevant. The callback should return TRUE if processing should go
    8218             :  * on, or FALSE if it should be interrupted.
    8219             :  *
    8220             :  * @param iGeomField Geometry field index.
    8221             :  * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
    8222             :  *                  OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
    8223             :  * @param[out] nEntryCountOut Number of entries in the returned array.
    8224             :  * @param pfnProgress Cancellation callback. May be NULL.
    8225             :  * @param pProgressData User data for the cancellation callback. May be NULL.
    8226             :  * @return an array of nEntryCount that must be freed with CPLFree(),
    8227             :  *         or NULL in case of error
    8228             :  * @since GDAL 3.6
    8229             :  */
    8230             : OGRGeometryTypeCounter *
    8231          12 : OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
    8232             :                            GDALProgressFunc pfnProgress, void *pProgressData)
    8233             : {
    8234          12 :     OGRFeatureDefn *poDefn = GetLayerDefn();
    8235          12 :     const int nGeomFieldCount = poDefn->GetGeomFieldCount();
    8236          12 :     if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
    8237             :     {
    8238           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
    8239           1 :         nEntryCountOut = 0;
    8240           1 :         return nullptr;
    8241             :     }
    8242             : 
    8243             :     // Ignore all fields but the geometry one of interest
    8244          22 :     CPLStringList aosIgnoredFieldsRestore;
    8245          22 :     CPLStringList aosIgnoredFields;
    8246          11 :     const int nFieldCount = poDefn->GetFieldCount();
    8247          33 :     for (int iField = 0; iField < nFieldCount; iField++)
    8248             :     {
    8249          22 :         const auto poFieldDefn = poDefn->GetFieldDefn(iField);
    8250          22 :         const char *pszName = poFieldDefn->GetNameRef();
    8251          22 :         if (poFieldDefn->IsIgnored())
    8252          10 :             aosIgnoredFieldsRestore.AddString(pszName);
    8253          22 :         if (iField != iGeomField)
    8254          11 :             aosIgnoredFields.AddString(pszName);
    8255             :     }
    8256          33 :     for (int iField = 0; iField < nGeomFieldCount; iField++)
    8257             :     {
    8258          22 :         const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
    8259          22 :         const char *pszName = poFieldDefn->GetNameRef();
    8260          22 :         if (poFieldDefn->IsIgnored())
    8261          10 :             aosIgnoredFieldsRestore.AddString(pszName);
    8262          22 :         if (iField != iGeomField)
    8263          11 :             aosIgnoredFields.AddString(pszName);
    8264             :     }
    8265          11 :     if (poDefn->IsStyleIgnored())
    8266           0 :         aosIgnoredFieldsRestore.AddString("OGR_STYLE");
    8267          11 :     aosIgnoredFields.AddString("OGR_STYLE");
    8268          11 :     SetIgnoredFields(aosIgnoredFields.List());
    8269             : 
    8270             :     // Iterate over features
    8271          22 :     std::map<OGRwkbGeometryType, int64_t> oMapCount;
    8272          22 :     std::set<OGRwkbGeometryType> oSetNotNull;
    8273          11 :     const bool bGeomCollectionZTInZ =
    8274          11 :         (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
    8275          11 :     const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
    8276          11 :     if (pfnProgress == GDALDummyProgress)
    8277           0 :         pfnProgress = nullptr;
    8278          11 :     bool bInterrupted = false;
    8279          47 :     for (auto &&poFeature : *this)
    8280             :     {
    8281          36 :         const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
    8282          36 :         if (poGeom == nullptr)
    8283             :         {
    8284          18 :             ++oMapCount[wkbNone];
    8285             :         }
    8286             :         else
    8287             :         {
    8288          18 :             auto eGeomType = poGeom->getGeometryType();
    8289          18 :             if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
    8290             :             {
    8291           1 :                 const auto poGC = poGeom->toGeometryCollection();
    8292           1 :                 if (poGC->getNumGeometries() > 0)
    8293             :                 {
    8294             :                     auto eSubGeomType =
    8295           1 :                         poGC->getGeometryRef(0)->getGeometryType();
    8296           1 :                     if (eSubGeomType == wkbTINZ)
    8297           1 :                         eGeomType = wkbTINZ;
    8298             :                 }
    8299             :             }
    8300          18 :             ++oMapCount[eGeomType];
    8301          18 :             if (bStopIfMixed)
    8302             :             {
    8303           4 :                 oSetNotNull.insert(eGeomType);
    8304           4 :                 if (oSetNotNull.size() == 2)
    8305           2 :                     break;
    8306             :             }
    8307             :         }
    8308          34 :         if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
    8309             :         {
    8310           1 :             bInterrupted = true;
    8311           1 :             break;
    8312             :         }
    8313             :     }
    8314             : 
    8315             :     // Restore ignore fields state
    8316          11 :     SetIgnoredFields(aosIgnoredFieldsRestore.List());
    8317             : 
    8318          11 :     if (bInterrupted)
    8319             :     {
    8320           1 :         nEntryCountOut = 0;
    8321           1 :         return nullptr;
    8322             :     }
    8323             : 
    8324             :     // Format result
    8325          10 :     nEntryCountOut = static_cast<int>(oMapCount.size());
    8326             :     OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
    8327          10 :         CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
    8328          10 :     int i = 0;
    8329          37 :     for (const auto &oIter : oMapCount)
    8330             :     {
    8331          27 :         pasRet[i].eGeomType = oIter.first;
    8332          27 :         pasRet[i].nCount = oIter.second;
    8333          27 :         ++i;
    8334             :     }
    8335          10 :     return pasRet;
    8336             : }
    8337             : 
    8338             : /************************************************************************/
    8339             : /*                       OGR_L_GetGeometryTypes()                       */
    8340             : /************************************************************************/
    8341             : 
    8342             : /** \brief Get actual geometry types found in features.
    8343             :  *
    8344             :  * See OGRLayer::GetGeometryTypes() for details.
    8345             :  *
    8346             :  * @param hLayer Layer.
    8347             :  * @param iGeomField Geometry field index.
    8348             :  * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
    8349             :  *               OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
    8350             :  * @param[out] pnEntryCount Pointer to the number of entries in the returned
    8351             :  *                          array. Must not be NULL.
    8352             :  * @param pfnProgress Cancellation callback. May be NULL.
    8353             :  * @param pProgressData User data for the cancellation callback. May be NULL.
    8354             :  * @return an array of *pnEntryCount that must be freed with CPLFree(),
    8355             :  *         or NULL in case of error
    8356             :  * @since GDAL 3.6
    8357             :  */
    8358          54 : OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
    8359             :                                                int nFlags, int *pnEntryCount,
    8360             :                                                GDALProgressFunc pfnProgress,
    8361             :                                                void *pProgressData)
    8362             : {
    8363          54 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
    8364          54 :     VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
    8365             : 
    8366         108 :     return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
    8367          54 :         iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
    8368             : }
    8369             : 
    8370             : /************************************************************************/
    8371             : /*                   OGRLayer::GetSupportedSRSList()                    */
    8372             : /************************************************************************/
    8373             : 
    8374             : /** \brief Get the list of SRS supported.
    8375             :  *
    8376             :  * The base implementation of this method will return an empty list. Some
    8377             :  * drivers (OAPIF, WFS) may return a non-empty list.
    8378             :  *
    8379             :  * One of the SRS returned may be passed to SetActiveSRS() to change the
    8380             :  * active SRS.
    8381             :  *
    8382             :  * @param iGeomField Geometry field index.
    8383             :  * @return list of supported SRS.
    8384             :  * @since GDAL 3.7
    8385             :  */
    8386             : const OGRLayer::GetSupportedSRSListRetType &
    8387         208 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
    8388             : {
    8389         208 :     static OGRLayer::GetSupportedSRSListRetType empty;
    8390         208 :     return empty;
    8391             : }
    8392             : 
    8393             : /************************************************************************/
    8394             : /*                     OGR_L_GetSupportedSRSList()                      */
    8395             : /************************************************************************/
    8396             : 
    8397             : /** \brief Get the list of SRS supported.
    8398             :  *
    8399             :  * The base implementation of this method will return an empty list. Some
    8400             :  * drivers (OAPIF, WFS) may return a non-empty list.
    8401             :  *
    8402             :  * One of the SRS returned may be passed to SetActiveSRS() to change the
    8403             :  * active SRS.
    8404             :  *
    8405             :  * @param hLayer Layer.
    8406             :  * @param iGeomField Geometry field index.
    8407             :  * @param[out] pnCount Number of values in returned array. Must not be null.
    8408             :  * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
    8409             :  * nullptr
    8410             :  * @since GDAL 3.7
    8411             :  */
    8412           4 : OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
    8413             :                                                 int iGeomField, int *pnCount)
    8414             : {
    8415           4 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
    8416           4 :     VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
    8417             : 
    8418             :     const auto &srsList =
    8419           4 :         OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
    8420           4 :     *pnCount = static_cast<int>(srsList.size());
    8421           4 :     if (srsList.empty())
    8422             :     {
    8423           2 :         return nullptr;
    8424             :     }
    8425             :     OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
    8426           2 :         CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
    8427           2 :     size_t i = 0;
    8428           7 :     for (const auto &poSRS : srsList)
    8429             :     {
    8430           5 :         poSRS->Reference();
    8431           5 :         pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
    8432           5 :         ++i;
    8433             :     }
    8434           2 :     pahRet[i] = nullptr;
    8435           2 :     return pahRet;
    8436             : }
    8437             : 
    8438             : /************************************************************************/
    8439             : /*                       OGRLayer::SetActiveSRS()                       */
    8440             : /************************************************************************/
    8441             : 
    8442             : /** \brief Change the active SRS.
    8443             :  *
    8444             :  * The passed SRS must be in the list returned by GetSupportedSRSList()
    8445             :  * (the actual pointer may be different, but should be tested as identical
    8446             :  * with OGRSpatialReference::IsSame()).
    8447             :  *
    8448             :  * Changing the active SRS affects:
    8449             :  * <ul>
    8450             :  * <li>the SRS in which geometries of returned features are expressed,</li>
    8451             :  * <li>the SRS in which geometries of passed features (CreateFeature(),
    8452             :  * SetFeature()) are expressed,</li>
    8453             :  * <li>the SRS returned by GetSpatialRef() and
    8454             :  * GetGeomFieldDefn()->GetSpatialRef(),</li>
    8455             :  * <li>the SRS used to interpret SetSpatialFilter() values.</li>
    8456             :  * </ul>
    8457             :  * This also resets feature reading and the spatial filter.
    8458             :  * Note however that this does not modify the storage SRS of the features of
    8459             :  * geometries. Said otherwise, this setting is volatile and has no persistent
    8460             :  * effects after dataset reopening.
    8461             :  *
    8462             :  * @param iGeomField Geometry field index.
    8463             :  * @param poSRS SRS to use
    8464             :  * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
    8465             :  *         the passed SRS is not in GetSupportedSRSList()
    8466             :  * @since GDAL 3.7
    8467             :  */
    8468           1 : OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
    8469             :                               CPL_UNUSED const OGRSpatialReference *poSRS)
    8470             : {
    8471           1 :     return OGRERR_FAILURE;
    8472             : }
    8473             : 
    8474             : /************************************************************************/
    8475             : /*                         OGR_L_SetActiveSRS()                         */
    8476             : /************************************************************************/
    8477             : 
    8478             : /** \brief Change the active SRS.
    8479             :  *
    8480             :  * The passed SRS must be in the list returned by GetSupportedSRSList()
    8481             :  * (the actual pointer may be different, but should be tested as identical
    8482             :  * with OGRSpatialReference::IsSame()).
    8483             :  *
    8484             :  * Changing the active SRS affects:
    8485             :  * <ul>
    8486             :  * <li>the SRS in which geometries of returned features are expressed,</li>
    8487             :  * <li>the SRS in which geometries of passed features (CreateFeature(),
    8488             :  * SetFeature()) are expressed,</li>
    8489             :  * <li>the SRS returned by GetSpatialRef() and
    8490             :  * GetGeomFieldDefn()->GetSpatialRef(),</li>
    8491             :  * <li>the SRS used to interpret SetSpatialFilter() values.</li>
    8492             :  * </ul>
    8493             :  * This also resets feature reading and the spatial filter.
    8494             :  * Note however that this does not modify the storage SRS of the features of
    8495             :  * geometries. Said otherwise, this setting is volatile and has no persistent
    8496             :  * effects after dataset reopening.
    8497             :  *
    8498             :  * @param hLayer Layer.
    8499             :  * @param iGeomField Geometry field index.
    8500             :  * @param hSRS SRS to use
    8501             :  * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
    8502             :  *         the passed SRS is not in GetSupportedSRSList().
    8503             :  * @since GDAL 3.7
    8504             :  */
    8505           9 : OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
    8506             :                           OGRSpatialReferenceH hSRS)
    8507             : {
    8508           9 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
    8509          18 :     return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
    8510           9 :         iGeomField, OGRSpatialReference::FromHandle(hSRS));
    8511             : }
    8512             : 
    8513             : /************************************************************************/
    8514             : /*                             GetDataset()                             */
    8515             : /************************************************************************/
    8516             : 
    8517             : /** Return the dataset associated with this layer.
    8518             :  *
    8519             :  * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
    8520             :  * have CreateLayer() capability. It may not be implemented in read-only
    8521             :  * drivers or out-of-tree drivers.
    8522             :  *
    8523             :  * It is currently only used by the GetRecordBatchSchema()
    8524             :  * method to retrieve the field domain associated with a field, to fill the
    8525             :  * dictionary field of a struct ArrowSchema.
    8526             :  * It is also used by CreateFieldFromArrowSchema() to determine which field
    8527             :  * types and subtypes are supported by the layer, by inspecting the driver
    8528             :  * metadata, and potentially use fallback types when needed.
    8529             :  *
    8530             :  * This method is the same as the C function OGR_L_GetDataset().
    8531             :  *
    8532             :  * @return dataset, or nullptr when unknown.
    8533             :  * @since GDAL 3.6
    8534             :  */
    8535          25 : GDALDataset *OGRLayer::GetDataset()
    8536             : {
    8537          25 :     return nullptr;
    8538             : }
    8539             : 
    8540             : /************************************************************************/
    8541             : /*                          OGR_L_GetDataset()                          */
    8542             : /************************************************************************/
    8543             : 
    8544             : /** Return the dataset associated with this layer.
    8545             :  *
    8546             :  * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
    8547             :  * have CreateLayer() capability. It may not be implemented in read-only
    8548             :  * drivers or out-of-tree drivers.
    8549             :  *
    8550             :  * It is currently only used by the GetRecordBatchSchema()
    8551             :  * method to retrieve the field domain associated with a field, to fill the
    8552             :  * dictionary field of a struct ArrowSchema.
    8553             :  * It is also used by CreateFieldFromArrowSchema() to determine which field
    8554             :  * types and subtypes are supported by the layer, by inspecting the driver
    8555             :  * metadata, and potentially use fallback types when needed.
    8556             :  *
    8557             :  * This function is the same as the C++ method OGRLayer::GetDataset().
    8558             :  *
    8559             :  * @return dataset, or nullptr when unknown.
    8560             :  * @since GDAL 3.9
    8561             :  */
    8562         264 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
    8563             : {
    8564         264 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
    8565         264 :     return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
    8566             : }

Generated by: LCOV version 1.14