LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1657 2113 78.4 %
Date: 2026-09-14 01:27:28 Functions: 133 153 86.9 %

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

Generated by: LCOV version 1.14