LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1614 2064 78.2 %
Date: 2026-01-21 22:42:07 Functions: 130 151 86.1 %

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

Generated by: LCOV version 1.14