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

Generated by: LCOV version 1.14