LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1622 2068 78.4 %
Date: 2026-03-05 10:33:42 Functions: 132 152 86.8 %

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

Generated by: LCOV version 1.14