LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1608 2051 78.4 %
Date: 2025-10-22 13:51:22 Functions: 128 147 87.1 %

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

Generated by: LCOV version 1.14