LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1550 1976 78.4 %
Date: 2024-11-21 22:18:42 Functions: 123 143 86.0 %

          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 <set>
      28             : 
      29             : /************************************************************************/
      30             : /*                              OGRLayer()                              */
      31             : /************************************************************************/
      32             : 
      33       68941 : OGRLayer::OGRLayer()
      34       68941 :     : m_poPrivate(new Private()), m_bFilterIsEnvelope(FALSE),
      35             :       m_poFilterGeom(nullptr),
      36             :       m_pPreparedFilterGeom(nullptr), m_sFilterEnvelope{},
      37             :       m_iGeomFieldFilter(0), m_poStyleTable(nullptr), m_poAttrQuery(nullptr),
      38             :       m_pszAttrQueryString(nullptr), m_poAttrIndex(nullptr), m_nRefCount(0),
      39      137882 :       m_nFeaturesRead(0)
      40             : {
      41       68941 : }
      42             : 
      43             : /************************************************************************/
      44             : /*                             ~OGRLayer()                              */
      45             : /************************************************************************/
      46             : 
      47       68932 : OGRLayer::~OGRLayer()
      48             : 
      49             : {
      50       68932 :     if (m_poStyleTable)
      51             :     {
      52          11 :         delete m_poStyleTable;
      53          11 :         m_poStyleTable = nullptr;
      54             :     }
      55             : 
      56       68932 :     if (m_poAttrIndex != nullptr)
      57             :     {
      58         162 :         delete m_poAttrIndex;
      59         162 :         m_poAttrIndex = nullptr;
      60             :     }
      61             : 
      62       68932 :     if (m_poAttrQuery != nullptr)
      63             :     {
      64         628 :         delete m_poAttrQuery;
      65         628 :         m_poAttrQuery = nullptr;
      66             :     }
      67             : 
      68       68932 :     CPLFree(m_pszAttrQueryString);
      69             : 
      70       68932 :     if (m_poFilterGeom)
      71             :     {
      72         838 :         delete m_poFilterGeom;
      73         838 :         m_poFilterGeom = nullptr;
      74             :     }
      75             : 
      76       68932 :     if (m_pPreparedFilterGeom != nullptr)
      77             :     {
      78         838 :         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
      79         838 :         m_pPreparedFilterGeom = nullptr;
      80             :     }
      81             : 
      82       68932 :     if (m_poSharedArrowArrayStreamPrivateData != nullptr)
      83             :     {
      84         658 :         m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
      85             :     }
      86       68932 : }
      87             : 
      88             : /************************************************************************/
      89             : /*                             Reference()                              */
      90             : /************************************************************************/
      91             : 
      92           0 : int OGRLayer::Reference()
      93             : 
      94             : {
      95           0 :     return ++m_nRefCount;
      96             : }
      97             : 
      98             : /************************************************************************/
      99             : /*                          OGR_L_Reference()                           */
     100             : /************************************************************************/
     101             : 
     102           0 : int OGR_L_Reference(OGRLayerH hLayer)
     103             : 
     104             : {
     105           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_Reference", 0);
     106             : 
     107           0 :     return OGRLayer::FromHandle(hLayer)->Reference();
     108             : }
     109             : 
     110             : /************************************************************************/
     111             : /*                            Dereference()                             */
     112             : /************************************************************************/
     113             : 
     114           0 : int OGRLayer::Dereference()
     115             : 
     116             : {
     117           0 :     return --m_nRefCount;
     118             : }
     119             : 
     120             : /************************************************************************/
     121             : /*                         OGR_L_Dereference()                          */
     122             : /************************************************************************/
     123             : 
     124           0 : int OGR_L_Dereference(OGRLayerH hLayer)
     125             : 
     126             : {
     127           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_Dereference", 0);
     128             : 
     129           0 :     return OGRLayer::FromHandle(hLayer)->Dereference();
     130             : }
     131             : 
     132             : /************************************************************************/
     133             : /*                            GetRefCount()                             */
     134             : /************************************************************************/
     135             : 
     136           0 : int OGRLayer::GetRefCount() const
     137             : 
     138             : {
     139           0 :     return m_nRefCount;
     140             : }
     141             : 
     142             : /************************************************************************/
     143             : /*                         OGR_L_GetRefCount()                          */
     144             : /************************************************************************/
     145             : 
     146           0 : int OGR_L_GetRefCount(OGRLayerH hLayer)
     147             : 
     148             : {
     149           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetRefCount", 0);
     150             : 
     151           0 :     return OGRLayer::FromHandle(hLayer)->GetRefCount();
     152             : }
     153             : 
     154             : /************************************************************************/
     155             : /*                         GetFeatureCount()                            */
     156             : /************************************************************************/
     157             : 
     158       13816 : GIntBig OGRLayer::GetFeatureCount(int bForce)
     159             : 
     160             : {
     161       13816 :     if (!bForce)
     162           1 :         return -1;
     163             : 
     164       13815 :     GIntBig nFeatureCount = 0;
     165       55631 :     for (auto &&poFeature : *this)
     166             :     {
     167       41816 :         CPL_IGNORE_RET_VAL(poFeature.get());
     168       41816 :         nFeatureCount++;
     169             :     }
     170       13815 :     ResetReading();
     171             : 
     172       13815 :     return nFeatureCount;
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*                      OGR_L_GetFeatureCount()                         */
     177             : /************************************************************************/
     178             : 
     179       36727 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
     180             : 
     181             : {
     182       36727 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
     183             : 
     184             : #ifdef OGRAPISPY_ENABLED
     185       36727 :     if (bOGRAPISpyEnabled)
     186           2 :         OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
     187             : #endif
     188             : 
     189       36727 :     return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
     190             : }
     191             : 
     192             : /************************************************************************/
     193             : /*                             GetExtent()                              */
     194             : /************************************************************************/
     195             : 
     196         438 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, int bForce)
     197             : 
     198             : {
     199         438 :     return GetExtentInternal(0, psExtent, bForce);
     200             : }
     201             : 
     202        1477 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
     203             : 
     204             : {
     205        1477 :     if (iGeomField == 0)
     206         956 :         return GetExtent(psExtent, bForce);
     207             :     else
     208         521 :         return GetExtentInternal(iGeomField, psExtent, bForce);
     209             : }
     210             : 
     211          28 : OGRErr OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
     212             :                              int bForce)
     213             : 
     214             : {
     215          28 :     psExtent3D->MinX = 0.0;
     216          28 :     psExtent3D->MaxX = 0.0;
     217          28 :     psExtent3D->MinY = 0.0;
     218          28 :     psExtent3D->MaxY = 0.0;
     219          28 :     psExtent3D->MinZ = std::numeric_limits<double>::infinity();
     220          28 :     psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
     221             : 
     222             :     /* -------------------------------------------------------------------- */
     223             :     /*      If this layer has a none geometry type, then we can             */
     224             :     /*      reasonably assume there are not extents available.              */
     225             :     /* -------------------------------------------------------------------- */
     226          55 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
     227          27 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
     228             :     {
     229           1 :         if (iGeomField != 0)
     230             :         {
     231           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     232             :                      "Invalid geometry field index : %d", iGeomField);
     233             :         }
     234           1 :         return OGRERR_FAILURE;
     235             :     }
     236             : 
     237             :     /* -------------------------------------------------------------------- */
     238             :     /*      If not forced, we should avoid having to scan all the           */
     239             :     /*      features and just return a failure.                             */
     240             :     /* -------------------------------------------------------------------- */
     241          27 :     if (!bForce)
     242           0 :         return OGRERR_FAILURE;
     243             : 
     244             :     /* -------------------------------------------------------------------- */
     245             :     /*      OK, we hate to do this, but go ahead and read through all       */
     246             :     /*      the features to collect geometries and build extents.           */
     247             :     /* -------------------------------------------------------------------- */
     248          27 :     OGREnvelope3D oEnv;
     249          27 :     bool bExtentSet = false;
     250             : 
     251         133 :     for (auto &&poFeature : *this)
     252             :     {
     253         106 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     254         106 :         if (poGeom == nullptr || poGeom->IsEmpty())
     255             :         {
     256             :             /* Do nothing */
     257             :         }
     258          89 :         else if (!bExtentSet)
     259             :         {
     260          27 :             poGeom->getEnvelope(psExtent3D);
     261             :             // This is required because getEnvelope initializes Z to 0 for 2D geometries
     262          27 :             if (!poGeom->Is3D())
     263             :             {
     264          20 :                 psExtent3D->MinZ = std::numeric_limits<double>::infinity();
     265          20 :                 psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
     266             :             }
     267          27 :             bExtentSet = true;
     268             :         }
     269             :         else
     270             :         {
     271          62 :             poGeom->getEnvelope(&oEnv);
     272             :             // This is required because getEnvelope initializes Z to 0 for 2D geometries
     273          62 :             if (!poGeom->Is3D())
     274             :             {
     275          53 :                 oEnv.MinZ = std::numeric_limits<double>::infinity();
     276          53 :                 oEnv.MaxZ = -std::numeric_limits<double>::infinity();
     277             :             }
     278             :             // Merge handles infinity correctly
     279          62 :             psExtent3D->Merge(oEnv);
     280             :         }
     281             :     }
     282          27 :     ResetReading();
     283             : 
     284          27 :     return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
     285             : }
     286             : 
     287             : //! @cond Doxygen_Suppress
     288        1018 : OGRErr OGRLayer::GetExtentInternal(int iGeomField, OGREnvelope *psExtent,
     289             :                                    int bForce)
     290             : 
     291             : {
     292        1018 :     psExtent->MinX = 0.0;
     293        1018 :     psExtent->MaxX = 0.0;
     294        1018 :     psExtent->MinY = 0.0;
     295        1018 :     psExtent->MaxY = 0.0;
     296             : 
     297             :     /* -------------------------------------------------------------------- */
     298             :     /*      If this layer has a none geometry type, then we can             */
     299             :     /*      reasonably assume there are not extents available.              */
     300             :     /* -------------------------------------------------------------------- */
     301        1426 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
     302         408 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
     303             :     {
     304         610 :         if (iGeomField != 0)
     305             :         {
     306         485 :             CPLError(CE_Failure, CPLE_AppDefined,
     307             :                      "Invalid geometry field index : %d", iGeomField);
     308             :         }
     309         610 :         return OGRERR_FAILURE;
     310             :     }
     311             : 
     312             :     /* -------------------------------------------------------------------- */
     313             :     /*      If not forced, we should avoid having to scan all the           */
     314             :     /*      features and just return a failure.                             */
     315             :     /* -------------------------------------------------------------------- */
     316         408 :     if (!bForce)
     317           1 :         return OGRERR_FAILURE;
     318             : 
     319             :     /* -------------------------------------------------------------------- */
     320             :     /*      OK, we hate to do this, but go ahead and read through all       */
     321             :     /*      the features to collect geometries and build extents.           */
     322             :     /* -------------------------------------------------------------------- */
     323         407 :     OGREnvelope oEnv;
     324         407 :     bool bExtentSet = false;
     325             : 
     326        9574 :     for (auto &&poFeature : *this)
     327             :     {
     328        9167 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     329        9167 :         if (poGeom == nullptr || poGeom->IsEmpty())
     330             :         {
     331             :             /* Do nothing */
     332             :         }
     333        8859 :         else if (!bExtentSet)
     334             :         {
     335         359 :             poGeom->getEnvelope(psExtent);
     336         718 :             if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
     337         359 :                   std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
     338             :             {
     339         359 :                 bExtentSet = true;
     340             :             }
     341             :         }
     342             :         else
     343             :         {
     344        8500 :             poGeom->getEnvelope(&oEnv);
     345        8500 :             if (oEnv.MinX < psExtent->MinX)
     346         297 :                 psExtent->MinX = oEnv.MinX;
     347        8500 :             if (oEnv.MinY < psExtent->MinY)
     348         438 :                 psExtent->MinY = oEnv.MinY;
     349        8500 :             if (oEnv.MaxX > psExtent->MaxX)
     350         882 :                 psExtent->MaxX = oEnv.MaxX;
     351        8500 :             if (oEnv.MaxY > psExtent->MaxY)
     352         854 :                 psExtent->MaxY = oEnv.MaxY;
     353             :         }
     354             :     }
     355         407 :     ResetReading();
     356             : 
     357         407 :     return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
     358             : }
     359             : 
     360             : //! @endcond
     361             : 
     362             : /************************************************************************/
     363             : /*                          OGR_L_GetExtent()                           */
     364             : /************************************************************************/
     365             : 
     366          51 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
     367             : 
     368             : {
     369          51 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
     370             : 
     371             : #ifdef OGRAPISPY_ENABLED
     372          51 :     if (bOGRAPISpyEnabled)
     373           0 :         OGRAPISpy_L_GetExtent(hLayer, bForce);
     374             : #endif
     375             : 
     376          51 :     return OGRLayer::FromHandle(hLayer)->GetExtent(psExtent, bForce);
     377             : }
     378             : 
     379             : /************************************************************************/
     380             : /*                         OGR_L_GetExtentEx()                          */
     381             : /************************************************************************/
     382             : 
     383         369 : OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
     384             :                          OGREnvelope *psExtent, int bForce)
     385             : 
     386             : {
     387         369 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
     388             : 
     389             : #ifdef OGRAPISPY_ENABLED
     390         369 :     if (bOGRAPISpyEnabled)
     391           4 :         OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
     392             : #endif
     393             : 
     394         738 :     return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
     395         369 :                                                    bForce);
     396             : }
     397             : 
     398             : /************************************************************************/
     399             : /*                          OGR_L_GetExtent3D()                           */
     400             : /************************************************************************/
     401             : 
     402          60 : OGRErr OGR_L_GetExtent3D(OGRLayerH hLayer, int iGeomField,
     403             :                          OGREnvelope3D *psExtent3D, int bForce)
     404             : 
     405             : {
     406          60 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent3D", OGRERR_INVALID_HANDLE);
     407             : 
     408             : #ifdef OGRAPISPY_ENABLED
     409          60 :     if (bOGRAPISpyEnabled)
     410           0 :         OGRAPISpy_L_GetExtent3D(hLayer, iGeomField, bForce);
     411             : #endif
     412             : 
     413         120 :     return OGRLayer::FromHandle(hLayer)->GetExtent3D(iGeomField, psExtent3D,
     414          60 :                                                      bForce);
     415             : }
     416             : 
     417             : /************************************************************************/
     418             : /*                         SetAttributeFilter()                         */
     419             : /************************************************************************/
     420             : 
     421       14708 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
     422             : 
     423             : {
     424       14708 :     CPLFree(m_pszAttrQueryString);
     425       14708 :     m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
     426             : 
     427             :     /* -------------------------------------------------------------------- */
     428             :     /*      Are we just clearing any existing query?                        */
     429             :     /* -------------------------------------------------------------------- */
     430       14708 :     if (pszQuery == nullptr || strlen(pszQuery) == 0)
     431             :     {
     432        9749 :         if (m_poAttrQuery)
     433             :         {
     434        2824 :             delete m_poAttrQuery;
     435        2824 :             m_poAttrQuery = nullptr;
     436        2824 :             ResetReading();
     437             :         }
     438        9749 :         return OGRERR_NONE;
     439             :     }
     440             : 
     441             :     /* -------------------------------------------------------------------- */
     442             :     /*      Or are we installing a new query?                               */
     443             :     /* -------------------------------------------------------------------- */
     444             :     OGRErr eErr;
     445             : 
     446        4959 :     if (!m_poAttrQuery)
     447        3510 :         m_poAttrQuery = new OGRFeatureQuery();
     448             : 
     449        4959 :     eErr = m_poAttrQuery->Compile(this, pszQuery);
     450        4959 :     if (eErr != OGRERR_NONE)
     451             :     {
     452           2 :         delete m_poAttrQuery;
     453           2 :         m_poAttrQuery = nullptr;
     454             :     }
     455             : 
     456        4959 :     ResetReading();
     457             : 
     458        4959 :     return eErr;
     459             : }
     460             : 
     461             : /************************************************************************/
     462             : /*                        ContainGeomSpecialField()                     */
     463             : /************************************************************************/
     464             : 
     465         272 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
     466             : {
     467         272 :     if (expr->eNodeType == SNT_COLUMN)
     468             :     {
     469          57 :         if (expr->table_index == 0 && expr->field_index != -1)
     470             :         {
     471          57 :             int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
     472          57 :             return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
     473         114 :                    nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
     474          57 :                    nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
     475             :         }
     476             :     }
     477         215 :     else if (expr->eNodeType == SNT_OPERATION)
     478             :     {
     479         327 :         for (int i = 0; i < expr->nSubExprCount; i++)
     480             :         {
     481         214 :             if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
     482           0 :                 return TRUE;
     483             :         }
     484             :     }
     485         215 :     return FALSE;
     486             : }
     487             : 
     488             : /************************************************************************/
     489             : /*                AttributeFilterEvaluationNeedsGeometry()              */
     490             : /************************************************************************/
     491             : 
     492             : //! @cond Doxygen_Suppress
     493          58 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
     494             : {
     495          58 :     if (!m_poAttrQuery)
     496           0 :         return FALSE;
     497             : 
     498             :     swq_expr_node *expr =
     499          58 :         static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
     500          58 :     int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
     501             : 
     502          58 :     return ContainGeomSpecialField(expr, nLayerFieldCount);
     503             : }
     504             : 
     505             : //! @endcond
     506             : 
     507             : /************************************************************************/
     508             : /*                      OGR_L_SetAttributeFilter()                      */
     509             : /************************************************************************/
     510             : 
     511        1441 : OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
     512             : 
     513             : {
     514        1441 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
     515             :                       OGRERR_INVALID_HANDLE);
     516             : 
     517             : #ifdef OGRAPISPY_ENABLED
     518        1441 :     if (bOGRAPISpyEnabled)
     519           4 :         OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
     520             : #endif
     521             : 
     522        1441 :     return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
     523             : }
     524             : 
     525             : /************************************************************************/
     526             : /*                             GetFeature()                             */
     527             : /************************************************************************/
     528             : 
     529         984 : OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
     530             : 
     531             : {
     532             :     /* Save old attribute and spatial filters */
     533             :     char *pszOldFilter =
     534         984 :         m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
     535             :     OGRGeometry *poOldFilterGeom =
     536         984 :         (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
     537         984 :     int iOldGeomFieldFilter = m_iGeomFieldFilter;
     538             :     /* Unset filters */
     539         984 :     SetAttributeFilter(nullptr);
     540         984 :     SetSpatialFilter(0, nullptr);
     541             : 
     542         984 :     OGRFeatureUniquePtr poFeature;
     543       14391 :     for (auto &&poFeatureIter : *this)
     544             :     {
     545       13407 :         if (poFeatureIter->GetFID() == nFID)
     546             :         {
     547         660 :             poFeature.swap(poFeatureIter);
     548         660 :             break;
     549             :         }
     550             :     }
     551             : 
     552             :     /* Restore filters */
     553         984 :     SetAttributeFilter(pszOldFilter);
     554         984 :     CPLFree(pszOldFilter);
     555         984 :     SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
     556         984 :     delete poOldFilterGeom;
     557             : 
     558        1968 :     return poFeature.release();
     559             : }
     560             : 
     561             : /************************************************************************/
     562             : /*                          OGR_L_GetFeature()                          */
     563             : /************************************************************************/
     564             : 
     565        2531 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
     566             : 
     567             : {
     568        2531 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
     569             : 
     570             : #ifdef OGRAPISPY_ENABLED
     571        2531 :     if (bOGRAPISpyEnabled)
     572           2 :         OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
     573             : #endif
     574             : 
     575        2531 :     return OGRFeature::ToHandle(
     576        5062 :         OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
     577             : }
     578             : 
     579             : /************************************************************************/
     580             : /*                           SetNextByIndex()                           */
     581             : /************************************************************************/
     582             : 
     583        1088 : OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
     584             : 
     585             : {
     586        1088 :     if (nIndex < 0)
     587         199 :         return OGRERR_FAILURE;
     588             : 
     589         889 :     ResetReading();
     590             : 
     591         889 :     OGRFeature *poFeature = nullptr;
     592      129391 :     while (nIndex-- > 0)
     593             :     {
     594      128701 :         poFeature = GetNextFeature();
     595      128701 :         if (poFeature == nullptr)
     596         199 :             return OGRERR_FAILURE;
     597             : 
     598      128502 :         delete poFeature;
     599             :     }
     600             : 
     601         690 :     return OGRERR_NONE;
     602             : }
     603             : 
     604             : /************************************************************************/
     605             : /*                        OGR_L_SetNextByIndex()                        */
     606             : /************************************************************************/
     607             : 
     608          39 : OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
     609             : 
     610             : {
     611          39 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
     612             : 
     613             : #ifdef OGRAPISPY_ENABLED
     614          39 :     if (bOGRAPISpyEnabled)
     615           2 :         OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
     616             : #endif
     617             : 
     618          39 :     return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
     619             : }
     620             : 
     621             : /************************************************************************/
     622             : /*                        OGR_L_GetNextFeature()                        */
     623             : /************************************************************************/
     624             : 
     625       82879 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
     626             : 
     627             : {
     628       82879 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
     629             : 
     630             : #ifdef OGRAPISPY_ENABLED
     631       82879 :     if (bOGRAPISpyEnabled)
     632           8 :         OGRAPISpy_L_GetNextFeature(hLayer);
     633             : #endif
     634             : 
     635       82879 :     return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
     636             : }
     637             : 
     638             : /************************************************************************/
     639             : /*                       ConvertGeomsIfNecessary()                      */
     640             : /************************************************************************/
     641             : 
     642      938751 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
     643             : {
     644      938751 :     if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
     645             :     {
     646             :         // One time initialization
     647        9153 :         m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
     648        9153 :         m_poPrivate->m_bSupportsCurve =
     649        9153 :             CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
     650        9153 :         m_poPrivate->m_bSupportsM =
     651        9153 :             CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
     652        9153 :         if (CPLTestBool(
     653             :                 CPLGetConfigOption("OGR_APPLY_GEOM_SET_PRECISION", "FALSE")))
     654             :         {
     655           2 :             const auto poFeatureDefn = GetLayerDefn();
     656           2 :             const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
     657           2 :             for (int i = 0; i < nGeomFieldCount; i++)
     658             :             {
     659           2 :                 const double dfXYResolution = poFeatureDefn->GetGeomFieldDefn(i)
     660           2 :                                                   ->GetCoordinatePrecision()
     661           2 :                                                   .dfXYResolution;
     662           4 :                 if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
     663           2 :                     OGRGeometryFactory::haveGEOS())
     664             :                 {
     665           2 :                     m_poPrivate->m_bApplyGeomSetPrecision = true;
     666           2 :                     break;
     667             :                 }
     668             :             }
     669             :         }
     670             :     }
     671             : 
     672     1786340 :     if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
     673      847592 :         m_poPrivate->m_bApplyGeomSetPrecision)
     674             :     {
     675       91161 :         const auto poFeatureDefn = GetLayerDefn();
     676       91161 :         const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
     677      181539 :         for (int i = 0; i < nGeomFieldCount; i++)
     678             :         {
     679       90378 :             OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
     680       90378 :             if (poGeom)
     681             :             {
     682      106072 :                 if (!m_poPrivate->m_bSupportsM &&
     683       18785 :                     OGR_GT_HasM(poGeom->getGeometryType()))
     684             :                 {
     685           1 :                     poGeom->setMeasured(FALSE);
     686             :                 }
     687             : 
     688      174329 :                 if (!m_poPrivate->m_bSupportsCurve &&
     689       87042 :                     OGR_GT_IsNonLinear(poGeom->getGeometryType()))
     690             :                 {
     691             :                     OGRwkbGeometryType eTargetType =
     692          23 :                         OGR_GT_GetLinear(poGeom->getGeometryType());
     693          23 :                     poGeom = OGRGeometryFactory::forceTo(
     694             :                         poFeature->StealGeometry(i), eTargetType);
     695          23 :                     poFeature->SetGeomFieldDirectly(i, poGeom);
     696          23 :                     poGeom = poFeature->GetGeomFieldRef(i);
     697             :                 }
     698             : 
     699       87287 :                 if (poGeom && m_poPrivate->m_bApplyGeomSetPrecision)
     700             :                 {
     701             :                     const double dfXYResolution =
     702           2 :                         poFeatureDefn->GetGeomFieldDefn(i)
     703           2 :                             ->GetCoordinatePrecision()
     704           2 :                             .dfXYResolution;
     705           4 :                     if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
     706           2 :                         !poGeom->hasCurveGeometry())
     707             :                     {
     708           2 :                         auto poNewGeom = poGeom->SetPrecision(dfXYResolution,
     709             :                                                               /* nFlags = */ 0);
     710           2 :                         if (poNewGeom)
     711             :                         {
     712           2 :                             poFeature->SetGeomFieldDirectly(i, poNewGeom);
     713             :                             // If there was potential further processing...
     714             :                             // poGeom = poFeature->GetGeomFieldRef(i);
     715             :                         }
     716             :                     }
     717             :                 }
     718             :             }
     719             :         }
     720             :     }
     721      938751 : }
     722             : 
     723             : /************************************************************************/
     724             : /*                             SetFeature()                             */
     725             : /************************************************************************/
     726             : 
     727        3572 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
     728             : 
     729             : {
     730        3572 :     ConvertGeomsIfNecessary(poFeature);
     731        3572 :     return ISetFeature(poFeature);
     732             : }
     733             : 
     734             : /************************************************************************/
     735             : /*                             ISetFeature()                            */
     736             : /************************************************************************/
     737             : 
     738         127 : OGRErr OGRLayer::ISetFeature(OGRFeature *)
     739             : 
     740             : {
     741         127 :     return OGRERR_UNSUPPORTED_OPERATION;
     742             : }
     743             : 
     744             : /************************************************************************/
     745             : /*                          OGR_L_SetFeature()                          */
     746             : /************************************************************************/
     747             : 
     748        2480 : OGRErr OGR_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
     749             : 
     750             : {
     751        2480 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
     752        2480 :     VALIDATE_POINTER1(hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
     753             : 
     754             : #ifdef OGRAPISPY_ENABLED
     755        2480 :     if (bOGRAPISpyEnabled)
     756           2 :         OGRAPISpy_L_SetFeature(hLayer, hFeat);
     757             : #endif
     758             : 
     759        2480 :     return OGRLayer::FromHandle(hLayer)->SetFeature(
     760        2480 :         OGRFeature::FromHandle(hFeat));
     761             : }
     762             : 
     763             : /************************************************************************/
     764             : /*                           CreateFeature()                            */
     765             : /************************************************************************/
     766             : 
     767      935068 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
     768             : 
     769             : {
     770      935068 :     ConvertGeomsIfNecessary(poFeature);
     771      935068 :     return ICreateFeature(poFeature);
     772             : }
     773             : 
     774             : /************************************************************************/
     775             : /*                           ICreateFeature()                            */
     776             : /************************************************************************/
     777             : 
     778           0 : OGRErr OGRLayer::ICreateFeature(OGRFeature *)
     779             : 
     780             : {
     781           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     782             : }
     783             : 
     784             : /************************************************************************/
     785             : /*                        OGR_L_CreateFeature()                         */
     786             : /************************************************************************/
     787             : 
     788      285460 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
     789             : 
     790             : {
     791      285460 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
     792      285460 :     VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
     793             : 
     794             : #ifdef OGRAPISPY_ENABLED
     795      285460 :     if (bOGRAPISpyEnabled)
     796           5 :         OGRAPISpy_L_CreateFeature(hLayer, hFeat);
     797             : #endif
     798             : 
     799      285460 :     return OGRLayer::FromHandle(hLayer)->CreateFeature(
     800      285460 :         OGRFeature::FromHandle(hFeat));
     801             : }
     802             : 
     803             : /************************************************************************/
     804             : /*                           UpsertFeature()                           */
     805             : /************************************************************************/
     806             : 
     807          32 : OGRErr OGRLayer::UpsertFeature(OGRFeature *poFeature)
     808             : 
     809             : {
     810          32 :     ConvertGeomsIfNecessary(poFeature);
     811          32 :     return IUpsertFeature(poFeature);
     812             : }
     813             : 
     814             : /************************************************************************/
     815             : /*                           IUpsertFeature()                           */
     816             : /************************************************************************/
     817             : 
     818           0 : OGRErr OGRLayer::IUpsertFeature(OGRFeature *)
     819             : {
     820           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     821             : }
     822             : 
     823             : /************************************************************************/
     824             : /*                        OGR_L_UpsertFeature()                         */
     825             : /************************************************************************/
     826             : 
     827          31 : OGRErr OGR_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
     828             : 
     829             : {
     830          31 :     VALIDATE_POINTER1(hLayer, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
     831          31 :     VALIDATE_POINTER1(hFeat, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
     832             : 
     833             : #ifdef OGRAPISPY_ENABLED
     834          31 :     if (bOGRAPISpyEnabled)
     835           0 :         OGRAPISpy_L_UpsertFeature(hLayer, hFeat);
     836             : #endif
     837             : 
     838          31 :     return OGRLayer::FromHandle(hLayer)->UpsertFeature(
     839          31 :         OGRFeature::FromHandle(hFeat));
     840             : }
     841             : 
     842             : /************************************************************************/
     843             : /*                           UpdateFeature()                            */
     844             : /************************************************************************/
     845             : 
     846          79 : OGRErr OGRLayer::UpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
     847             :                                const int *panUpdatedFieldsIdx,
     848             :                                int nUpdatedGeomFieldsCount,
     849             :                                const int *panUpdatedGeomFieldsIdx,
     850             :                                bool bUpdateStyleString)
     851             : 
     852             : {
     853          79 :     ConvertGeomsIfNecessary(poFeature);
     854          79 :     const int nFieldCount = GetLayerDefn()->GetFieldCount();
     855         144 :     for (int i = 0; i < nUpdatedFieldsCount; ++i)
     856             :     {
     857          67 :         if (panUpdatedFieldsIdx[i] < 0 || panUpdatedFieldsIdx[i] >= nFieldCount)
     858             :         {
     859           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     860             :                      "Invalid panUpdatedFieldsIdx[%d] = %d", i,
     861           2 :                      panUpdatedFieldsIdx[i]);
     862           2 :             return OGRERR_FAILURE;
     863             :         }
     864             :     }
     865          77 :     const int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
     866          87 :     for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
     867             :     {
     868          12 :         if (panUpdatedGeomFieldsIdx[i] < 0 ||
     869          11 :             panUpdatedGeomFieldsIdx[i] >= nGeomFieldCount)
     870             :         {
     871           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     872             :                      "Invalid panUpdatedGeomFieldsIdx[%d] = %d", i,
     873           2 :                      panUpdatedGeomFieldsIdx[i]);
     874           2 :             return OGRERR_FAILURE;
     875             :         }
     876             :     }
     877          75 :     return IUpdateFeature(poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
     878             :                           nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx,
     879          75 :                           bUpdateStyleString);
     880             : }
     881             : 
     882             : /************************************************************************/
     883             : /*                           IUpdateFeature()                           */
     884             : /************************************************************************/
     885             : 
     886          28 : OGRErr OGRLayer::IUpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
     887             :                                 const int *panUpdatedFieldsIdx,
     888             :                                 int nUpdatedGeomFieldsCount,
     889             :                                 const int *panUpdatedGeomFieldsIdx,
     890             :                                 bool bUpdateStyleString)
     891             : {
     892          28 :     if (!TestCapability(OLCRandomWrite))
     893           0 :         return OGRERR_UNSUPPORTED_OPERATION;
     894             : 
     895             :     auto poFeatureExisting =
     896          56 :         std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID()));
     897          28 :     if (!poFeatureExisting)
     898           1 :         return OGRERR_NON_EXISTING_FEATURE;
     899             : 
     900          52 :     for (int i = 0; i < nUpdatedFieldsCount; ++i)
     901             :     {
     902          25 :         poFeatureExisting->SetField(
     903          25 :             panUpdatedFieldsIdx[i],
     904          25 :             poFeature->GetRawFieldRef(panUpdatedFieldsIdx[i]));
     905             :     }
     906          29 :     for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
     907             :     {
     908           2 :         poFeatureExisting->SetGeomFieldDirectly(
     909           2 :             panUpdatedGeomFieldsIdx[i],
     910           2 :             poFeature->StealGeometry(panUpdatedGeomFieldsIdx[i]));
     911             :     }
     912          27 :     if (bUpdateStyleString)
     913             :     {
     914           0 :         poFeatureExisting->SetStyleString(poFeature->GetStyleString());
     915             :     }
     916          27 :     return ISetFeature(poFeatureExisting.get());
     917             : }
     918             : 
     919             : /************************************************************************/
     920             : /*                        OGR_L_UpdateFeature()                         */
     921             : /************************************************************************/
     922             : 
     923          31 : OGRErr OGR_L_UpdateFeature(OGRLayerH hLayer, OGRFeatureH hFeat,
     924             :                            int nUpdatedFieldsCount,
     925             :                            const int *panUpdatedFieldsIdx,
     926             :                            int nUpdatedGeomFieldsCount,
     927             :                            const int *panUpdatedGeomFieldsIdx,
     928             :                            bool bUpdateStyleString)
     929             : 
     930             : {
     931          31 :     VALIDATE_POINTER1(hLayer, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
     932          31 :     VALIDATE_POINTER1(hFeat, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
     933             : 
     934          31 :     return OGRLayer::FromHandle(hLayer)->UpdateFeature(
     935             :         OGRFeature::FromHandle(hFeat), nUpdatedFieldsCount, panUpdatedFieldsIdx,
     936          31 :         nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
     937             : }
     938             : 
     939             : /************************************************************************/
     940             : /*                            CreateField()                             */
     941             : /************************************************************************/
     942             : 
     943          80 : OGRErr OGRLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
     944             : 
     945             : {
     946             :     (void)poField;
     947             :     (void)bApproxOK;
     948             : 
     949          80 :     CPLError(CE_Failure, CPLE_NotSupported,
     950             :              "CreateField() not supported by this layer.\n");
     951             : 
     952          80 :     return OGRERR_UNSUPPORTED_OPERATION;
     953             : }
     954             : 
     955             : /************************************************************************/
     956             : /*                         OGR_L_CreateField()                          */
     957             : /************************************************************************/
     958             : 
     959       77734 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
     960             : 
     961             : {
     962       77734 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
     963       77734 :     VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
     964             : 
     965             : #ifdef OGRAPISPY_ENABLED
     966       77734 :     if (bOGRAPISpyEnabled)
     967           6 :         OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
     968             : #endif
     969             : 
     970      155468 :     return OGRLayer::FromHandle(hLayer)->CreateField(
     971       77734 :         OGRFieldDefn::FromHandle(hField), bApproxOK);
     972             : }
     973             : 
     974             : /************************************************************************/
     975             : /*                            DeleteField()                             */
     976             : /************************************************************************/
     977             : 
     978           0 : OGRErr OGRLayer::DeleteField(int iField)
     979             : 
     980             : {
     981             :     (void)iField;
     982             : 
     983           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     984             :              "DeleteField() not supported by this layer.\n");
     985             : 
     986           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     987             : }
     988             : 
     989             : /************************************************************************/
     990             : /*                         OGR_L_DeleteField()                          */
     991             : /************************************************************************/
     992             : 
     993          69 : OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
     994             : 
     995             : {
     996          69 :     VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
     997             : 
     998             : #ifdef OGRAPISPY_ENABLED
     999          69 :     if (bOGRAPISpyEnabled)
    1000           2 :         OGRAPISpy_L_DeleteField(hLayer, iField);
    1001             : #endif
    1002             : 
    1003          69 :     return OGRLayer::FromHandle(hLayer)->DeleteField(iField);
    1004             : }
    1005             : 
    1006             : /************************************************************************/
    1007             : /*                           ReorderFields()                            */
    1008             : /************************************************************************/
    1009             : 
    1010           0 : OGRErr OGRLayer::ReorderFields(int *panMap)
    1011             : 
    1012             : {
    1013             :     (void)panMap;
    1014             : 
    1015           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1016             :              "ReorderFields() not supported by this layer.\n");
    1017             : 
    1018           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1019             : }
    1020             : 
    1021             : /************************************************************************/
    1022             : /*                       OGR_L_ReorderFields()                          */
    1023             : /************************************************************************/
    1024             : 
    1025          43 : OGRErr OGR_L_ReorderFields(OGRLayerH hLayer, int *panMap)
    1026             : 
    1027             : {
    1028          43 :     VALIDATE_POINTER1(hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE);
    1029             : 
    1030             : #ifdef OGRAPISPY_ENABLED
    1031          43 :     if (bOGRAPISpyEnabled)
    1032           2 :         OGRAPISpy_L_ReorderFields(hLayer, panMap);
    1033             : #endif
    1034             : 
    1035          43 :     return OGRLayer::FromHandle(hLayer)->ReorderFields(panMap);
    1036             : }
    1037             : 
    1038             : /************************************************************************/
    1039             : /*                            ReorderField()                            */
    1040             : /************************************************************************/
    1041             : 
    1042          34 : OGRErr OGRLayer::ReorderField(int iOldFieldPos, int iNewFieldPos)
    1043             : 
    1044             : {
    1045             :     OGRErr eErr;
    1046             : 
    1047          34 :     int nFieldCount = GetLayerDefn()->GetFieldCount();
    1048             : 
    1049          34 :     if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
    1050             :     {
    1051           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    1052           0 :         return OGRERR_FAILURE;
    1053             :     }
    1054          34 :     if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
    1055             :     {
    1056           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    1057           0 :         return OGRERR_FAILURE;
    1058             :     }
    1059          34 :     if (iNewFieldPos == iOldFieldPos)
    1060           0 :         return OGRERR_NONE;
    1061             : 
    1062          34 :     int *panMap = static_cast<int *>(CPLMalloc(sizeof(int) * nFieldCount));
    1063          34 :     if (iOldFieldPos < iNewFieldPos)
    1064             :     {
    1065             :         /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
    1066          15 :         int i = 0;  // Used after for.
    1067          19 :         for (; i < iOldFieldPos; i++)
    1068           4 :             panMap[i] = i;
    1069          40 :         for (; i < iNewFieldPos; i++)
    1070          25 :             panMap[i] = i + 1;
    1071          15 :         panMap[iNewFieldPos] = iOldFieldPos;
    1072          27 :         for (i = iNewFieldPos + 1; i < nFieldCount; i++)
    1073          12 :             panMap[i] = i;
    1074             :     }
    1075             :     else
    1076             :     {
    1077             :         /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
    1078          23 :         for (int i = 0; i < iNewFieldPos; i++)
    1079           4 :             panMap[i] = i;
    1080          19 :         panMap[iNewFieldPos] = iOldFieldPos;
    1081          19 :         int i = iNewFieldPos + 1;  // Used after for.
    1082          67 :         for (; i <= iOldFieldPos; i++)
    1083          48 :             panMap[i] = i - 1;
    1084          31 :         for (; i < nFieldCount; i++)
    1085          12 :             panMap[i] = i;
    1086             :     }
    1087             : 
    1088          34 :     eErr = ReorderFields(panMap);
    1089             : 
    1090          34 :     CPLFree(panMap);
    1091             : 
    1092          34 :     return eErr;
    1093             : }
    1094             : 
    1095             : /************************************************************************/
    1096             : /*                        OGR_L_ReorderField()                          */
    1097             : /************************************************************************/
    1098             : 
    1099          34 : OGRErr OGR_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos)
    1100             : 
    1101             : {
    1102          34 :     VALIDATE_POINTER1(hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE);
    1103             : 
    1104             : #ifdef OGRAPISPY_ENABLED
    1105          34 :     if (bOGRAPISpyEnabled)
    1106           2 :         OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
    1107             : #endif
    1108             : 
    1109          34 :     return OGRLayer::FromHandle(hLayer)->ReorderField(iOldFieldPos,
    1110          34 :                                                       iNewFieldPos);
    1111             : }
    1112             : 
    1113             : /************************************************************************/
    1114             : /*                           AlterFieldDefn()                           */
    1115             : /************************************************************************/
    1116             : 
    1117           0 : OGRErr OGRLayer::AlterFieldDefn(int /* iField*/,
    1118             :                                 OGRFieldDefn * /*poNewFieldDefn*/,
    1119             :                                 int /* nFlags */)
    1120             : 
    1121             : {
    1122           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1123             :              "AlterFieldDefn() not supported by this layer.\n");
    1124             : 
    1125           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1126             : }
    1127             : 
    1128             : /************************************************************************/
    1129             : /*                        OGR_L_AlterFieldDefn()                        */
    1130             : /************************************************************************/
    1131             : 
    1132         118 : OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
    1133             :                             OGRFieldDefnH hNewFieldDefn, int nFlags)
    1134             : 
    1135             : {
    1136         118 :     VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
    1137         118 :     VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
    1138             :                       OGRERR_INVALID_HANDLE);
    1139             : 
    1140             : #ifdef OGRAPISPY_ENABLED
    1141         118 :     if (bOGRAPISpyEnabled)
    1142           2 :         OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
    1143             : #endif
    1144             : 
    1145         236 :     return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
    1146         118 :         iField, OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags);
    1147             : }
    1148             : 
    1149             : /************************************************************************/
    1150             : /*                        AlterGeomFieldDefn()                          */
    1151             : /************************************************************************/
    1152             : 
    1153             : OGRErr
    1154           0 : OGRLayer::AlterGeomFieldDefn(int /* iGeomField*/,
    1155             :                              const OGRGeomFieldDefn * /*poNewGeomFieldDefn*/,
    1156             :                              int /* nFlags */)
    1157             : 
    1158             : {
    1159           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1160             :              "AlterGeomFieldDefn() not supported by this layer.\n");
    1161             : 
    1162           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1163             : }
    1164             : 
    1165             : /************************************************************************/
    1166             : /*                      OGR_L_AlterGeomFieldDefn()                      */
    1167             : /************************************************************************/
    1168             : 
    1169          33 : OGRErr OGR_L_AlterGeomFieldDefn(OGRLayerH hLayer, int iGeomField,
    1170             :                                 OGRGeomFieldDefnH hNewGeomFieldDefn, int nFlags)
    1171             : 
    1172             : {
    1173          33 :     VALIDATE_POINTER1(hLayer, "OGR_L_AlterGeomFieldDefn",
    1174             :                       OGRERR_INVALID_HANDLE);
    1175          33 :     VALIDATE_POINTER1(hNewGeomFieldDefn, "OGR_L_AlterGeomFieldDefn",
    1176             :                       OGRERR_INVALID_HANDLE);
    1177             : 
    1178          66 :     return OGRLayer::FromHandle(hLayer)->AlterGeomFieldDefn(
    1179             :         iGeomField,
    1180             :         const_cast<const OGRGeomFieldDefn *>(
    1181          33 :             OGRGeomFieldDefn::FromHandle(hNewGeomFieldDefn)),
    1182          33 :         nFlags);
    1183             : }
    1184             : 
    1185             : /************************************************************************/
    1186             : /*                         CreateGeomField()                            */
    1187             : /************************************************************************/
    1188             : 
    1189           0 : OGRErr OGRLayer::CreateGeomField(const OGRGeomFieldDefn *poField, int bApproxOK)
    1190             : 
    1191             : {
    1192             :     (void)poField;
    1193             :     (void)bApproxOK;
    1194             : 
    1195           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1196             :              "CreateGeomField() not supported by this layer.\n");
    1197             : 
    1198           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    1199             : }
    1200             : 
    1201             : /************************************************************************/
    1202             : /*                        OGR_L_CreateGeomField()                       */
    1203             : /************************************************************************/
    1204             : 
    1205         118 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
    1206             :                              int bApproxOK)
    1207             : 
    1208             : {
    1209         118 :     VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
    1210         118 :     VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
    1211             : 
    1212             : #ifdef OGRAPISPY_ENABLED
    1213         118 :     if (bOGRAPISpyEnabled)
    1214           2 :         OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
    1215             : #endif
    1216             : 
    1217         236 :     return OGRLayer::FromHandle(hLayer)->CreateGeomField(
    1218         118 :         OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
    1219             : }
    1220             : 
    1221             : /************************************************************************/
    1222             : /*                          StartTransaction()                          */
    1223             : /************************************************************************/
    1224             : 
    1225         585 : OGRErr OGRLayer::StartTransaction()
    1226             : 
    1227             : {
    1228         585 :     return OGRERR_NONE;
    1229             : }
    1230             : 
    1231             : /************************************************************************/
    1232             : /*                       OGR_L_StartTransaction()                       */
    1233             : /************************************************************************/
    1234             : 
    1235         157 : OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
    1236             : 
    1237             : {
    1238         157 :     VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
    1239             : 
    1240             : #ifdef OGRAPISPY_ENABLED
    1241         157 :     if (bOGRAPISpyEnabled)
    1242           2 :         OGRAPISpy_L_StartTransaction(hLayer);
    1243             : #endif
    1244             : 
    1245         157 :     return OGRLayer::FromHandle(hLayer)->StartTransaction();
    1246             : }
    1247             : 
    1248             : /************************************************************************/
    1249             : /*                         CommitTransaction()                          */
    1250             : /************************************************************************/
    1251             : 
    1252         537 : OGRErr OGRLayer::CommitTransaction()
    1253             : 
    1254             : {
    1255         537 :     return OGRERR_NONE;
    1256             : }
    1257             : 
    1258             : /************************************************************************/
    1259             : /*                       OGR_L_CommitTransaction()                      */
    1260             : /************************************************************************/
    1261             : 
    1262         137 : OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
    1263             : 
    1264             : {
    1265         137 :     VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
    1266             : 
    1267             : #ifdef OGRAPISPY_ENABLED
    1268         137 :     if (bOGRAPISpyEnabled)
    1269           2 :         OGRAPISpy_L_CommitTransaction(hLayer);
    1270             : #endif
    1271             : 
    1272         137 :     return OGRLayer::FromHandle(hLayer)->CommitTransaction();
    1273             : }
    1274             : 
    1275             : /************************************************************************/
    1276             : /*                        RollbackTransaction()                         */
    1277             : /************************************************************************/
    1278             : 
    1279          51 : OGRErr OGRLayer::RollbackTransaction()
    1280             : 
    1281             : {
    1282          51 :     return OGRERR_UNSUPPORTED_OPERATION;
    1283             : }
    1284             : 
    1285             : /************************************************************************/
    1286             : /*                     OGR_L_RollbackTransaction()                      */
    1287             : /************************************************************************/
    1288             : 
    1289          26 : OGRErr OGR_L_RollbackTransaction(OGRLayerH hLayer)
    1290             : 
    1291             : {
    1292          26 :     VALIDATE_POINTER1(hLayer, "OGR_L_RollbackTransaction",
    1293             :                       OGRERR_INVALID_HANDLE);
    1294             : 
    1295             : #ifdef OGRAPISPY_ENABLED
    1296          26 :     if (bOGRAPISpyEnabled)
    1297           2 :         OGRAPISpy_L_RollbackTransaction(hLayer);
    1298             : #endif
    1299             : 
    1300          26 :     return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
    1301             : }
    1302             : 
    1303             : /************************************************************************/
    1304             : /*                         OGR_L_GetLayerDefn()                         */
    1305             : /************************************************************************/
    1306             : 
    1307      127766 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
    1308             : 
    1309             : {
    1310      127766 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
    1311             : 
    1312             : #ifdef OGRAPISPY_ENABLED
    1313      127766 :     if (bOGRAPISpyEnabled)
    1314          15 :         OGRAPISpy_L_GetLayerDefn(hLayer);
    1315             : #endif
    1316             : 
    1317      127766 :     return OGRFeatureDefn::ToHandle(
    1318      255532 :         OGRLayer::FromHandle(hLayer)->GetLayerDefn());
    1319             : }
    1320             : 
    1321             : /************************************************************************/
    1322             : /*                         OGR_L_FindFieldIndex()                       */
    1323             : /************************************************************************/
    1324             : 
    1325           2 : int OGR_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
    1326             :                          int bExactMatch)
    1327             : 
    1328             : {
    1329           2 :     VALIDATE_POINTER1(hLayer, "OGR_L_FindFieldIndex", -1);
    1330             : 
    1331             : #ifdef OGRAPISPY_ENABLED
    1332           2 :     if (bOGRAPISpyEnabled)
    1333           2 :         OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
    1334             : #endif
    1335             : 
    1336           4 :     return OGRLayer::FromHandle(hLayer)->FindFieldIndex(pszFieldName,
    1337           2 :                                                         bExactMatch);
    1338             : }
    1339             : 
    1340             : /************************************************************************/
    1341             : /*                           FindFieldIndex()                           */
    1342             : /************************************************************************/
    1343             : 
    1344         100 : int OGRLayer::FindFieldIndex(const char *pszFieldName,
    1345             :                              CPL_UNUSED int bExactMatch)
    1346             : {
    1347         100 :     return GetLayerDefn()->GetFieldIndex(pszFieldName);
    1348             : }
    1349             : 
    1350             : /************************************************************************/
    1351             : /*                           GetSpatialRef()                            */
    1352             : /************************************************************************/
    1353             : 
    1354      423917 : OGRSpatialReference *OGRLayer::GetSpatialRef()
    1355             : {
    1356      423917 :     if (GetLayerDefn()->GetGeomFieldCount() > 0)
    1357             :         return const_cast<OGRSpatialReference *>(
    1358      423460 :             GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef());
    1359             :     else
    1360         457 :         return nullptr;
    1361             : }
    1362             : 
    1363             : /************************************************************************/
    1364             : /*                        OGR_L_GetSpatialRef()                         */
    1365             : /************************************************************************/
    1366             : 
    1367        1020 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
    1368             : 
    1369             : {
    1370        1020 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
    1371             : 
    1372             : #ifdef OGRAPISPY_ENABLED
    1373        1020 :     if (bOGRAPISpyEnabled)
    1374           2 :         OGRAPISpy_L_GetSpatialRef(hLayer);
    1375             : #endif
    1376             : 
    1377        1020 :     return OGRSpatialReference::ToHandle(
    1378        2040 :         OGRLayer::FromHandle(hLayer)->GetSpatialRef());
    1379             : }
    1380             : 
    1381             : /************************************************************************/
    1382             : /*                        OGR_L_TestCapability()                        */
    1383             : /************************************************************************/
    1384             : 
    1385         821 : int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
    1386             : 
    1387             : {
    1388         821 :     VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
    1389         821 :     VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
    1390             : 
    1391             : #ifdef OGRAPISPY_ENABLED
    1392         821 :     if (bOGRAPISpyEnabled)
    1393           2 :         OGRAPISpy_L_TestCapability(hLayer, pszCap);
    1394             : #endif
    1395             : 
    1396         821 :     return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
    1397             : }
    1398             : 
    1399             : /************************************************************************/
    1400             : /*                          GetSpatialFilter()                          */
    1401             : /************************************************************************/
    1402             : 
    1403         388 : OGRGeometry *OGRLayer::GetSpatialFilter()
    1404             : 
    1405             : {
    1406         388 :     return m_poFilterGeom;
    1407             : }
    1408             : 
    1409             : /************************************************************************/
    1410             : /*                       OGR_L_GetSpatialFilter()                       */
    1411             : /************************************************************************/
    1412             : 
    1413           5 : OGRGeometryH OGR_L_GetSpatialFilter(OGRLayerH hLayer)
    1414             : 
    1415             : {
    1416           5 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialFilter", nullptr);
    1417             : 
    1418             : #ifdef OGRAPISPY_ENABLED
    1419           5 :     if (bOGRAPISpyEnabled)
    1420           2 :         OGRAPISpy_L_GetSpatialFilter(hLayer);
    1421             : #endif
    1422             : 
    1423           5 :     return OGRGeometry::ToHandle(
    1424          10 :         OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
    1425             : }
    1426             : 
    1427             : /************************************************************************/
    1428             : /*             ValidateGeometryFieldIndexForSetSpatialFilter()          */
    1429             : /************************************************************************/
    1430             : 
    1431             : //! @cond Doxygen_Suppress
    1432       30922 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
    1433             :     int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
    1434             : {
    1435       31334 :     if (iGeomField == 0 && poGeomIn == nullptr &&
    1436         412 :         GetLayerDefn()->GetGeomFieldCount() == 0)
    1437             :     {
    1438             :         // Setting a null spatial filter on geometry field idx 0
    1439             :         // when there are no geometry field can't harm, and is accepted silently
    1440             :         // for backward compatibility with existing practice.
    1441             :     }
    1442       61592 :     else if (iGeomField < 0 ||
    1443       30692 :              iGeomField >= GetLayerDefn()->GetGeomFieldCount())
    1444             :     {
    1445         497 :         if (iGeomField == 0)
    1446             :         {
    1447          79 :             CPLError(
    1448             :                 CE_Failure, CPLE_AppDefined,
    1449             :                 bIsSelectLayer
    1450             :                     ? "Cannot set spatial filter: no geometry field selected."
    1451             :                     : "Cannot set spatial filter: no geometry field present in "
    1452             :                       "layer.");
    1453             :         }
    1454             :         else
    1455             :         {
    1456         418 :             CPLError(CE_Failure, CPLE_AppDefined,
    1457             :                      "Cannot set spatial filter on non-existing geometry field "
    1458             :                      "of index %d.",
    1459             :                      iGeomField);
    1460             :         }
    1461         497 :         return false;
    1462             :     }
    1463       30425 :     return true;
    1464             : }
    1465             : 
    1466             : //! @endcond
    1467             : 
    1468             : /************************************************************************/
    1469             : /*                          SetSpatialFilter()                          */
    1470             : /************************************************************************/
    1471             : 
    1472       36123 : void OGRLayer::SetSpatialFilter(OGRGeometry *poGeomIn)
    1473             : 
    1474             : {
    1475       36123 :     if (poGeomIn && !ValidateGeometryFieldIndexForSetSpatialFilter(0, poGeomIn))
    1476          77 :         return;
    1477             : 
    1478       36046 :     m_iGeomFieldFilter = 0;
    1479       36046 :     if (InstallFilter(poGeomIn))
    1480       28198 :         ResetReading();
    1481             : }
    1482             : 
    1483        6873 : void OGRLayer::SetSpatialFilter(int iGeomField, OGRGeometry *poGeomIn)
    1484             : 
    1485             : {
    1486        6873 :     if (iGeomField == 0)
    1487             :     {
    1488        8079 :         if (poGeomIn &&
    1489        1958 :             !ValidateGeometryFieldIndexForSetSpatialFilter(0, poGeomIn))
    1490           0 :             return;
    1491             : 
    1492        6121 :         m_iGeomFieldFilter = iGeomField;
    1493        6121 :         SetSpatialFilter(poGeomIn);
    1494             :     }
    1495             :     else
    1496             :     {
    1497         752 :         if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
    1498             :                                                            poGeomIn))
    1499         394 :             return;
    1500             : 
    1501         358 :         m_iGeomFieldFilter = iGeomField;
    1502         358 :         if (InstallFilter(poGeomIn))
    1503         198 :             ResetReading();
    1504             :     }
    1505             : }
    1506             : 
    1507             : /************************************************************************/
    1508             : /*                       OGR_L_SetSpatialFilter()                       */
    1509             : /************************************************************************/
    1510             : 
    1511         644 : void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
    1512             : 
    1513             : {
    1514         644 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
    1515             : 
    1516             : #ifdef OGRAPISPY_ENABLED
    1517         644 :     if (bOGRAPISpyEnabled)
    1518           4 :         OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
    1519             : #endif
    1520             : 
    1521        1288 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
    1522         644 :         OGRGeometry::FromHandle(hGeom));
    1523             : }
    1524             : 
    1525             : /************************************************************************/
    1526             : /*                      OGR_L_SetSpatialFilterEx()                      */
    1527             : /************************************************************************/
    1528             : 
    1529          12 : void OGR_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
    1530             :                               OGRGeometryH hGeom)
    1531             : 
    1532             : {
    1533          12 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterEx");
    1534             : 
    1535             : #ifdef OGRAPISPY_ENABLED
    1536          12 :     if (bOGRAPISpyEnabled)
    1537           2 :         OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
    1538             : #endif
    1539             : 
    1540          24 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
    1541          12 :         iGeomField, OGRGeometry::FromHandle(hGeom));
    1542             : }
    1543             : 
    1544             : /************************************************************************/
    1545             : /*                        SetSpatialFilterRect()                        */
    1546             : /************************************************************************/
    1547             : 
    1548       48036 : void OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY, double dfMaxX,
    1549             :                                     double dfMaxY)
    1550             : 
    1551             : {
    1552       48036 :     SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
    1553       48036 : }
    1554             : 
    1555       48095 : void OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
    1556             :                                     double dfMinY, double dfMaxX, double dfMaxY)
    1557             : 
    1558             : {
    1559       96190 :     OGRLinearRing oRing;
    1560       96190 :     OGRPolygon oPoly;
    1561             : 
    1562       48095 :     oRing.addPoint(dfMinX, dfMinY);
    1563       48095 :     oRing.addPoint(dfMinX, dfMaxY);
    1564       48095 :     oRing.addPoint(dfMaxX, dfMaxY);
    1565       48095 :     oRing.addPoint(dfMaxX, dfMinY);
    1566       48095 :     oRing.addPoint(dfMinX, dfMinY);
    1567             : 
    1568       48095 :     oPoly.addRing(&oRing);
    1569             : 
    1570       48095 :     if (iGeomField == 0)
    1571             :         /* for drivers that only overload SetSpatialFilter(OGRGeometry*) */
    1572       48077 :         SetSpatialFilter(&oPoly);
    1573             :     else
    1574          18 :         SetSpatialFilter(iGeomField, &oPoly);
    1575       48095 : }
    1576             : 
    1577             : /************************************************************************/
    1578             : /*                     OGR_L_SetSpatialFilterRect()                     */
    1579             : /************************************************************************/
    1580             : 
    1581       47751 : void OGR_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX, double dfMinY,
    1582             :                                 double dfMaxX, double dfMaxY)
    1583             : 
    1584             : {
    1585       47751 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRect");
    1586             : 
    1587             : #ifdef OGRAPISPY_ENABLED
    1588       47751 :     if (bOGRAPISpyEnabled)
    1589           2 :         OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX,
    1590             :                                          dfMaxY);
    1591             : #endif
    1592             : 
    1593       47751 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX,
    1594       47751 :                                                        dfMaxY);
    1595             : }
    1596             : 
    1597             : /************************************************************************/
    1598             : /*                    OGR_L_SetSpatialFilterRectEx()                    */
    1599             : /************************************************************************/
    1600             : 
    1601          15 : void OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
    1602             :                                   double dfMinX, double dfMinY, double dfMaxX,
    1603             :                                   double dfMaxY)
    1604             : 
    1605             : {
    1606          15 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRectEx");
    1607             : 
    1608             : #ifdef OGRAPISPY_ENABLED
    1609          15 :     if (bOGRAPISpyEnabled)
    1610           2 :         OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY,
    1611             :                                            dfMaxX, dfMaxY);
    1612             : #endif
    1613             : 
    1614          15 :     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(iGeomField, dfMinX,
    1615          15 :                                                        dfMinY, dfMaxX, dfMaxY);
    1616             : }
    1617             : 
    1618             : /************************************************************************/
    1619             : /*                           InstallFilter()                            */
    1620             : /*                                                                      */
    1621             : /*      This method is only intended to be used from within             */
    1622             : /*      drivers, normally from the SetSpatialFilter() method.           */
    1623             : /*      It installs a filter, and also tests it to see if it is         */
    1624             : /*      rectangular.  If so, it this is kept track of alongside the     */
    1625             : /*      filter geometry itself so we can do cheaper comparisons in      */
    1626             : /*      the FilterGeometry() call.                                      */
    1627             : /*                                                                      */
    1628             : /*      Returns TRUE if the newly installed filter differs in some      */
    1629             : /*      way from the current one.                                       */
    1630             : /************************************************************************/
    1631             : 
    1632             : //! @cond Doxygen_Suppress
    1633       64081 : int OGRLayer::InstallFilter(OGRGeometry *poFilter)
    1634             : 
    1635             : {
    1636       64081 :     if (m_poFilterGeom == poFilter)
    1637       10182 :         return FALSE;
    1638             : 
    1639             :     /* -------------------------------------------------------------------- */
    1640             :     /*      Replace the existing filter.                                    */
    1641             :     /* -------------------------------------------------------------------- */
    1642       53899 :     if (m_poFilterGeom != nullptr)
    1643             :     {
    1644       51064 :         delete m_poFilterGeom;
    1645       51064 :         m_poFilterGeom = nullptr;
    1646             :     }
    1647             : 
    1648       53899 :     if (m_pPreparedFilterGeom != nullptr)
    1649             :     {
    1650       51064 :         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
    1651       51064 :         m_pPreparedFilterGeom = nullptr;
    1652             :     }
    1653             : 
    1654       53899 :     if (poFilter != nullptr)
    1655       51902 :         m_poFilterGeom = poFilter->clone();
    1656             : 
    1657       53899 :     m_bFilterIsEnvelope = FALSE;
    1658             : 
    1659       53899 :     if (m_poFilterGeom == nullptr)
    1660        1997 :         return TRUE;
    1661             : 
    1662       51902 :     m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
    1663             : 
    1664             :     /* Compile geometry filter as a prepared geometry */
    1665       51902 :     m_pPreparedFilterGeom =
    1666       51902 :         OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
    1667             : 
    1668       51902 :     m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
    1669             : 
    1670       51902 :     return TRUE;
    1671             : }
    1672             : 
    1673             : //! @endcond
    1674             : 
    1675             : /************************************************************************/
    1676             : /*                   DoesGeometryHavePointInEnvelope()                  */
    1677             : /************************************************************************/
    1678             : 
    1679        5271 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
    1680             :                                             const OGREnvelope &sEnvelope)
    1681             : {
    1682        5271 :     const OGRLineString *poLS = nullptr;
    1683             : 
    1684        5271 :     switch (wkbFlatten(poGeometry->getGeometryType()))
    1685             :     {
    1686          36 :         case wkbPoint:
    1687             :         {
    1688          36 :             const auto poPoint = poGeometry->toPoint();
    1689          36 :             const double x = poPoint->getX();
    1690          36 :             const double y = poPoint->getY();
    1691          31 :             return (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
    1692          67 :                     x <= sEnvelope.MaxX && y <= sEnvelope.MaxY);
    1693             :         }
    1694             : 
    1695         393 :         case wkbLineString:
    1696         393 :             poLS = poGeometry->toLineString();
    1697         393 :             break;
    1698             : 
    1699        4138 :         case wkbPolygon:
    1700             :         {
    1701        4138 :             const OGRPolygon *poPoly = poGeometry->toPolygon();
    1702        4138 :             poLS = poPoly->getExteriorRing();
    1703        4138 :             break;
    1704             :         }
    1705             : 
    1706         463 :         case wkbMultiPoint:
    1707             :         case wkbMultiLineString:
    1708             :         case wkbMultiPolygon:
    1709             :         case wkbGeometryCollection:
    1710             :         {
    1711         694 :             for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
    1712             :             {
    1713         609 :                 if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
    1714         378 :                     return true;
    1715             :             }
    1716          85 :             return false;
    1717             :         }
    1718             : 
    1719         241 :         default:
    1720         241 :             return false;
    1721             :     }
    1722             : 
    1723        4531 :     if (poLS != nullptr)
    1724             :     {
    1725        4531 :         const int nNumPoints = poLS->getNumPoints();
    1726       52624 :         for (int i = 0; i < nNumPoints; i++)
    1727             :         {
    1728       51522 :             const double x = poLS->getX(i);
    1729       51522 :             const double y = poLS->getY(i);
    1730       51522 :             if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
    1731       20294 :                 x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
    1732             :             {
    1733        3429 :                 return true;
    1734             :             }
    1735             :         }
    1736             :     }
    1737             : 
    1738        1102 :     return false;
    1739             : }
    1740             : 
    1741             : /************************************************************************/
    1742             : /*                           FilterGeometry()                           */
    1743             : /*                                                                      */
    1744             : /*      Compare the passed in geometry to the currently installed       */
    1745             : /*      filter.  Optimize for case where filter is just an              */
    1746             : /*      envelope.                                                       */
    1747             : /************************************************************************/
    1748             : 
    1749             : //! @cond Doxygen_Suppress
    1750      452090 : int OGRLayer::FilterGeometry(const OGRGeometry *poGeometry)
    1751             : 
    1752             : {
    1753             :     /* -------------------------------------------------------------------- */
    1754             :     /*      In trivial cases of new filter or target geometry, we accept    */
    1755             :     /*      an intersection.  No geometry is taken to mean "the whole       */
    1756             :     /*      world".                                                         */
    1757             :     /* -------------------------------------------------------------------- */
    1758      452090 :     if (m_poFilterGeom == nullptr)
    1759         372 :         return TRUE;
    1760             : 
    1761      451718 :     if (poGeometry == nullptr || poGeometry->IsEmpty())
    1762         301 :         return FALSE;
    1763             : 
    1764             :     /* -------------------------------------------------------------------- */
    1765             :     /*      Compute the target geometry envelope, and if there is no        */
    1766             :     /*      intersection between the envelopes we are sure not to have      */
    1767             :     /*      any intersection.                                               */
    1768             :     /* -------------------------------------------------------------------- */
    1769      451417 :     OGREnvelope sGeomEnv;
    1770             : 
    1771      451417 :     poGeometry->getEnvelope(&sGeomEnv);
    1772             : 
    1773      451417 :     if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
    1774      297480 :         sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
    1775      230264 :         m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
    1776      130909 :         m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
    1777      337240 :         return FALSE;
    1778             : 
    1779             :     /* -------------------------------------------------------------------- */
    1780             :     /*      If the filter geometry is its own envelope and if the           */
    1781             :     /*      envelope of the geometry is inside the filter geometry,         */
    1782             :     /*      the geometry itself is inside the filter geometry               */
    1783             :     /* -------------------------------------------------------------------- */
    1784      114177 :     if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
    1785      110807 :         sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
    1786      109667 :         sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
    1787      108832 :         sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
    1788             :     {
    1789      108454 :         return TRUE;
    1790             :     }
    1791             :     else
    1792             :     {
    1793             :         // If the filter geometry is its own envelope and if the geometry has
    1794             :         // at least one point inside the filter geometry, the geometry itself
    1795             :         // intersects the filter geometry.
    1796        5723 :         if (m_bFilterIsEnvelope)
    1797             :         {
    1798        4662 :             if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
    1799        3439 :                 return true;
    1800             :         }
    1801             : 
    1802             :         /* --------------------------------------------------------------------
    1803             :          */
    1804             :         /*      Fallback to full intersect test (using GEOS) if we still */
    1805             :         /*      don't know for sure. */
    1806             :         /* --------------------------------------------------------------------
    1807             :          */
    1808        2284 :         if (OGRGeometryFactory::haveGEOS())
    1809             :         {
    1810             :             // CPLDebug("OGRLayer", "GEOS intersection");
    1811        2284 :             if (m_pPreparedFilterGeom != nullptr)
    1812        2284 :                 return OGRPreparedGeometryIntersects(
    1813             :                     m_pPreparedFilterGeom,
    1814             :                     OGRGeometry::ToHandle(
    1815        2284 :                         const_cast<OGRGeometry *>(poGeometry)));
    1816             :             else
    1817           0 :                 return m_poFilterGeom->Intersects(poGeometry);
    1818             :         }
    1819             :         else
    1820           0 :             return TRUE;
    1821             :     }
    1822             : }
    1823             : 
    1824             : /************************************************************************/
    1825             : /*                         FilterWKBGeometry()                          */
    1826             : /************************************************************************/
    1827             : 
    1828         230 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
    1829             :                                  bool bEnvelopeAlreadySet,
    1830             :                                  OGREnvelope &sEnvelope) const
    1831             : {
    1832         230 :     OGRPreparedGeometry *pPreparedFilterGeom = m_pPreparedFilterGeom;
    1833         460 :     bool bRet = FilterWKBGeometry(
    1834         230 :         pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope, m_poFilterGeom,
    1835         230 :         m_bFilterIsEnvelope, m_sFilterEnvelope, pPreparedFilterGeom);
    1836         230 :     const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
    1837         230 :     return bRet;
    1838             : }
    1839             : 
    1840             : /* static */
    1841         334 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
    1842             :                                  bool bEnvelopeAlreadySet,
    1843             :                                  OGREnvelope &sEnvelope,
    1844             :                                  const OGRGeometry *poFilterGeom,
    1845             :                                  bool bFilterIsEnvelope,
    1846             :                                  const OGREnvelope &sFilterEnvelope,
    1847             :                                  OGRPreparedGeometry *&pPreparedFilterGeom)
    1848             : {
    1849         334 :     if (!poFilterGeom)
    1850           0 :         return true;
    1851             : 
    1852         637 :     if ((bEnvelopeAlreadySet ||
    1853         668 :          OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
    1854         334 :         sFilterEnvelope.Intersects(sEnvelope))
    1855             :     {
    1856         161 :         if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
    1857             :         {
    1858          98 :             return true;
    1859             :         }
    1860             :         else
    1861             :         {
    1862         126 :             if (bFilterIsEnvelope &&
    1863          63 :                 OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
    1864             :             {
    1865          51 :                 return true;
    1866             :             }
    1867          12 :             else if (OGRGeometryFactory::haveGEOS())
    1868             :             {
    1869          12 :                 OGRGeometry *poGeom = nullptr;
    1870          12 :                 int ret = FALSE;
    1871          12 :                 if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
    1872          12 :                                                       nWKBSize) == OGRERR_NONE)
    1873             :                 {
    1874          12 :                     if (!pPreparedFilterGeom)
    1875             :                     {
    1876           0 :                         pPreparedFilterGeom =
    1877           0 :                             OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
    1878             :                                 const_cast<OGRGeometry *>(poFilterGeom)));
    1879             :                     }
    1880          12 :                     if (pPreparedFilterGeom)
    1881          12 :                         ret = OGRPreparedGeometryIntersects(
    1882             :                             pPreparedFilterGeom,
    1883             :                             OGRGeometry::ToHandle(
    1884             :                                 const_cast<OGRGeometry *>(poGeom)));
    1885             :                     else
    1886           0 :                         ret = poFilterGeom->Intersects(poGeom);
    1887             :                 }
    1888          12 :                 delete poGeom;
    1889          12 :                 return CPL_TO_BOOL(ret);
    1890             :             }
    1891             :             else
    1892             :             {
    1893             :                 // Assume intersection
    1894           0 :                 return true;
    1895             :             }
    1896             :         }
    1897             :     }
    1898             : 
    1899         173 :     return false;
    1900             : }
    1901             : 
    1902             : //! @endcond
    1903             : 
    1904             : /************************************************************************/
    1905             : /*                         OGR_L_ResetReading()                         */
    1906             : /************************************************************************/
    1907             : 
    1908       17655 : void OGR_L_ResetReading(OGRLayerH hLayer)
    1909             : 
    1910             : {
    1911       17655 :     VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
    1912             : 
    1913             : #ifdef OGRAPISPY_ENABLED
    1914       17655 :     if (bOGRAPISpyEnabled)
    1915           2 :         OGRAPISpy_L_ResetReading(hLayer);
    1916             : #endif
    1917             : 
    1918       17655 :     OGRLayer::FromHandle(hLayer)->ResetReading();
    1919             : }
    1920             : 
    1921             : /************************************************************************/
    1922             : /*                       InitializeIndexSupport()                       */
    1923             : /*                                                                      */
    1924             : /*      This is only intended to be called by driver layer              */
    1925             : /*      implementations but we don't make it protected so that the      */
    1926             : /*      datasources can do it too if that is more appropriate.          */
    1927             : /************************************************************************/
    1928             : 
    1929             : //! @cond Doxygen_Suppress
    1930             : OGRErr
    1931         646 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
    1932             : 
    1933             : {
    1934             : #ifdef HAVE_MITAB
    1935             :     OGRErr eErr;
    1936             : 
    1937         646 :     if (m_poAttrIndex != nullptr)
    1938         484 :         return OGRERR_NONE;
    1939             : 
    1940         162 :     m_poAttrIndex = OGRCreateDefaultLayerIndex();
    1941             : 
    1942         162 :     eErr = m_poAttrIndex->Initialize(pszFilename, this);
    1943         162 :     if (eErr != OGRERR_NONE)
    1944             :     {
    1945           0 :         delete m_poAttrIndex;
    1946           0 :         m_poAttrIndex = nullptr;
    1947             :     }
    1948             : 
    1949         162 :     return eErr;
    1950             : #else
    1951             :     return OGRERR_FAILURE;
    1952             : #endif
    1953             : }
    1954             : 
    1955             : //! @endcond
    1956             : 
    1957             : /************************************************************************/
    1958             : /*                             SyncToDisk()                             */
    1959             : /************************************************************************/
    1960             : 
    1961        4741 : OGRErr OGRLayer::SyncToDisk()
    1962             : 
    1963             : {
    1964        4741 :     return OGRERR_NONE;
    1965             : }
    1966             : 
    1967             : /************************************************************************/
    1968             : /*                          OGR_L_SyncToDisk()                          */
    1969             : /************************************************************************/
    1970             : 
    1971         251 : OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
    1972             : 
    1973             : {
    1974         251 :     VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
    1975             : 
    1976             : #ifdef OGRAPISPY_ENABLED
    1977         251 :     if (bOGRAPISpyEnabled)
    1978           2 :         OGRAPISpy_L_SyncToDisk(hLayer);
    1979             : #endif
    1980             : 
    1981         251 :     return OGRLayer::FromHandle(hLayer)->SyncToDisk();
    1982             : }
    1983             : 
    1984             : /************************************************************************/
    1985             : /*                           DeleteFeature()                            */
    1986             : /************************************************************************/
    1987             : 
    1988         286 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
    1989             : {
    1990         286 :     return OGRERR_UNSUPPORTED_OPERATION;
    1991             : }
    1992             : 
    1993             : /************************************************************************/
    1994             : /*                        OGR_L_DeleteFeature()                         */
    1995             : /************************************************************************/
    1996             : 
    1997        3336 : OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
    1998             : 
    1999             : {
    2000        3336 :     VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
    2001             : 
    2002             : #ifdef OGRAPISPY_ENABLED
    2003        3336 :     if (bOGRAPISpyEnabled)
    2004           2 :         OGRAPISpy_L_DeleteFeature(hLayer, nFID);
    2005             : #endif
    2006             : 
    2007        3336 :     return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
    2008             : }
    2009             : 
    2010             : /************************************************************************/
    2011             : /*                          GetFeaturesRead()                           */
    2012             : /************************************************************************/
    2013             : 
    2014             : //! @cond Doxygen_Suppress
    2015           0 : GIntBig OGRLayer::GetFeaturesRead()
    2016             : 
    2017             : {
    2018           0 :     return m_nFeaturesRead;
    2019             : }
    2020             : 
    2021             : //! @endcond
    2022             : 
    2023             : /************************************************************************/
    2024             : /*                       OGR_L_GetFeaturesRead()                        */
    2025             : /************************************************************************/
    2026             : 
    2027           0 : GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
    2028             : 
    2029             : {
    2030           0 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
    2031             : 
    2032           0 :     return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
    2033             : }
    2034             : 
    2035             : /************************************************************************/
    2036             : /*                             GetFIDColumn                             */
    2037             : /************************************************************************/
    2038             : 
    2039        7266 : const char *OGRLayer::GetFIDColumn()
    2040             : 
    2041             : {
    2042        7266 :     return "";
    2043             : }
    2044             : 
    2045             : /************************************************************************/
    2046             : /*                         OGR_L_GetFIDColumn()                         */
    2047             : /************************************************************************/
    2048             : 
    2049         383 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
    2050             : 
    2051             : {
    2052         383 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
    2053             : 
    2054             : #ifdef OGRAPISPY_ENABLED
    2055         383 :     if (bOGRAPISpyEnabled)
    2056           2 :         OGRAPISpy_L_GetFIDColumn(hLayer);
    2057             : #endif
    2058             : 
    2059         383 :     return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
    2060             : }
    2061             : 
    2062             : /************************************************************************/
    2063             : /*                         GetGeometryColumn()                          */
    2064             : /************************************************************************/
    2065             : 
    2066        3355 : const char *OGRLayer::GetGeometryColumn()
    2067             : 
    2068             : {
    2069        3355 :     if (GetLayerDefn()->GetGeomFieldCount() > 0)
    2070        3277 :         return GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef();
    2071             :     else
    2072          78 :         return "";
    2073             : }
    2074             : 
    2075             : /************************************************************************/
    2076             : /*                      OGR_L_GetGeometryColumn()                       */
    2077             : /************************************************************************/
    2078             : 
    2079         580 : const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
    2080             : 
    2081             : {
    2082         580 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
    2083             : 
    2084             : #ifdef OGRAPISPY_ENABLED
    2085         580 :     if (bOGRAPISpyEnabled)
    2086           2 :         OGRAPISpy_L_GetGeometryColumn(hLayer);
    2087             : #endif
    2088             : 
    2089         580 :     return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
    2090             : }
    2091             : 
    2092             : /************************************************************************/
    2093             : /*                            GetStyleTable()                           */
    2094             : /************************************************************************/
    2095             : 
    2096         846 : OGRStyleTable *OGRLayer::GetStyleTable()
    2097             : {
    2098         846 :     return m_poStyleTable;
    2099             : }
    2100             : 
    2101             : /************************************************************************/
    2102             : /*                         SetStyleTableDirectly()                      */
    2103             : /************************************************************************/
    2104             : 
    2105           0 : void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
    2106             : {
    2107           0 :     if (m_poStyleTable)
    2108           0 :         delete m_poStyleTable;
    2109           0 :     m_poStyleTable = poStyleTable;
    2110           0 : }
    2111             : 
    2112             : /************************************************************************/
    2113             : /*                            SetStyleTable()                           */
    2114             : /************************************************************************/
    2115             : 
    2116         843 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
    2117             : {
    2118         843 :     if (m_poStyleTable)
    2119           0 :         delete m_poStyleTable;
    2120         843 :     if (poStyleTable)
    2121           1 :         m_poStyleTable = poStyleTable->Clone();
    2122         843 : }
    2123             : 
    2124             : /************************************************************************/
    2125             : /*                         OGR_L_GetStyleTable()                        */
    2126             : /************************************************************************/
    2127             : 
    2128           3 : OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
    2129             : 
    2130             : {
    2131           3 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
    2132             : 
    2133             :     return reinterpret_cast<OGRStyleTableH>(
    2134           3 :         OGRLayer::FromHandle(hLayer)->GetStyleTable());
    2135             : }
    2136             : 
    2137             : /************************************************************************/
    2138             : /*                         OGR_L_SetStyleTableDirectly()                */
    2139             : /************************************************************************/
    2140             : 
    2141           0 : void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
    2142             : 
    2143             : {
    2144           0 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
    2145             : 
    2146           0 :     OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
    2147           0 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    2148             : }
    2149             : 
    2150             : /************************************************************************/
    2151             : /*                         OGR_L_SetStyleTable()                        */
    2152             : /************************************************************************/
    2153             : 
    2154           1 : void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
    2155             : 
    2156             : {
    2157           1 :     VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
    2158           1 :     VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
    2159             : 
    2160           1 :     OGRLayer::FromHandle(hLayer)->SetStyleTable(
    2161           1 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    2162             : }
    2163             : 
    2164             : /************************************************************************/
    2165             : /*                               GetName()                              */
    2166             : /************************************************************************/
    2167             : 
    2168     1126520 : const char *OGRLayer::GetName()
    2169             : 
    2170             : {
    2171     1126520 :     return GetLayerDefn()->GetName();
    2172             : }
    2173             : 
    2174             : /************************************************************************/
    2175             : /*                           OGR_L_GetName()                            */
    2176             : /************************************************************************/
    2177             : 
    2178        1419 : const char *OGR_L_GetName(OGRLayerH hLayer)
    2179             : 
    2180             : {
    2181        1419 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
    2182             : 
    2183             : #ifdef OGRAPISPY_ENABLED
    2184        1419 :     if (bOGRAPISpyEnabled)
    2185           2 :         OGRAPISpy_L_GetName(hLayer);
    2186             : #endif
    2187             : 
    2188        1419 :     return OGRLayer::FromHandle(hLayer)->GetName();
    2189             : }
    2190             : 
    2191             : /************************************************************************/
    2192             : /*                            GetGeomType()                             */
    2193             : /************************************************************************/
    2194             : 
    2195      217477 : OGRwkbGeometryType OGRLayer::GetGeomType()
    2196             : {
    2197      217477 :     OGRFeatureDefn *poLayerDefn = GetLayerDefn();
    2198      217477 :     if (poLayerDefn == nullptr)
    2199             :     {
    2200           0 :         CPLDebug("OGR", "GetLayerType() returns NULL !");
    2201           0 :         return wkbUnknown;
    2202             :     }
    2203      217477 :     return poLayerDefn->GetGeomType();
    2204             : }
    2205             : 
    2206             : /************************************************************************/
    2207             : /*                         OGR_L_GetGeomType()                          */
    2208             : /************************************************************************/
    2209             : 
    2210        1104 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
    2211             : 
    2212             : {
    2213        1104 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
    2214             : 
    2215             : #ifdef OGRAPISPY_ENABLED
    2216        1104 :     if (bOGRAPISpyEnabled)
    2217           2 :         OGRAPISpy_L_GetGeomType(hLayer);
    2218             : #endif
    2219             : 
    2220        1104 :     OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
    2221        1104 :     if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
    2222             :     {
    2223           1 :         eType = OGR_GT_GetLinear(eType);
    2224             :     }
    2225        1104 :     return eType;
    2226             : }
    2227             : 
    2228             : /************************************************************************/
    2229             : /*                          SetIgnoredFields()                          */
    2230             : /************************************************************************/
    2231             : 
    2232        8402 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
    2233             : {
    2234        8402 :     OGRFeatureDefn *poDefn = GetLayerDefn();
    2235             : 
    2236             :     // first set everything as *not* ignored
    2237       63314 :     for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
    2238             :     {
    2239       54912 :         poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
    2240             :     }
    2241       19559 :     for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
    2242             :     {
    2243       11157 :         poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
    2244             :     }
    2245        8402 :     poDefn->SetStyleIgnored(FALSE);
    2246             : 
    2247             :     // ignore some fields
    2248       15970 :     for (const char *pszFieldName : cpl::Iterate(papszFields))
    2249             :     {
    2250             :         // check special fields
    2251        7568 :         if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
    2252         154 :             poDefn->SetGeometryIgnored(TRUE);
    2253        7414 :         else if (EQUAL(pszFieldName, "OGR_STYLE"))
    2254          13 :             poDefn->SetStyleIgnored(TRUE);
    2255             :         else
    2256             :         {
    2257             :             // check ordinary fields
    2258        7401 :             int iField = poDefn->GetFieldIndex(pszFieldName);
    2259        7401 :             if (iField == -1)
    2260             :             {
    2261             :                 // check geometry field
    2262        1660 :                 iField = poDefn->GetGeomFieldIndex(pszFieldName);
    2263        1660 :                 if (iField == -1)
    2264             :                 {
    2265           0 :                     return OGRERR_FAILURE;
    2266             :                 }
    2267             :                 else
    2268        1660 :                     poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
    2269             :             }
    2270             :             else
    2271        5741 :                 poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
    2272             :         }
    2273             :     }
    2274             : 
    2275        8402 :     return OGRERR_NONE;
    2276             : }
    2277             : 
    2278             : /************************************************************************/
    2279             : /*                       OGR_L_SetIgnoredFields()                       */
    2280             : /************************************************************************/
    2281             : 
    2282         265 : OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
    2283             : 
    2284             : {
    2285         265 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
    2286             : 
    2287             : #ifdef OGRAPISPY_ENABLED
    2288         265 :     if (bOGRAPISpyEnabled)
    2289           2 :         OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
    2290             : #endif
    2291             : 
    2292         265 :     return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
    2293             : }
    2294             : 
    2295             : /************************************************************************/
    2296             : /*                             Rename()                                 */
    2297             : /************************************************************************/
    2298             : 
    2299             : /** Rename layer.
    2300             :  *
    2301             :  * This operation is implemented only by layers that expose the OLCRename
    2302             :  * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
    2303             :  *
    2304             :  * This operation will fail if a layer with the new name already exists.
    2305             :  *
    2306             :  * On success, GetDescription() and GetLayerDefn()->GetName() will return
    2307             :  * pszNewName.
    2308             :  *
    2309             :  * Renaming the layer may interrupt current feature iteration.
    2310             :  *
    2311             :  * @param pszNewName New layer name. Must not be NULL.
    2312             :  * @return OGRERR_NONE in case of success
    2313             :  *
    2314             :  * @since GDAL 3.5
    2315             :  */
    2316           0 : OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
    2317             : {
    2318           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    2319             :              "Rename() not supported by this layer.");
    2320             : 
    2321           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    2322             : }
    2323             : 
    2324             : /************************************************************************/
    2325             : /*                           OGR_L_Rename()                             */
    2326             : /************************************************************************/
    2327             : 
    2328             : /** Rename layer.
    2329             :  *
    2330             :  * This operation is implemented only by layers that expose the OLCRename
    2331             :  * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
    2332             :  *
    2333             :  * This operation will fail if a layer with the new name already exists.
    2334             :  *
    2335             :  * On success, GetDescription() and GetLayerDefn()->GetName() will return
    2336             :  * pszNewName.
    2337             :  *
    2338             :  * Renaming the layer may interrupt current feature iteration.
    2339             :  *
    2340             :  * @param hLayer     Layer to rename.
    2341             :  * @param pszNewName New layer name. Must not be NULL.
    2342             :  * @return OGRERR_NONE in case of success
    2343             :  *
    2344             :  * @since GDAL 3.5
    2345             :  */
    2346          37 : OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
    2347             : 
    2348             : {
    2349          37 :     VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
    2350          37 :     VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
    2351             : 
    2352          37 :     return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
    2353             : }
    2354             : 
    2355             : /************************************************************************/
    2356             : /*         helper functions for layer overlay methods                   */
    2357             : /************************************************************************/
    2358             : 
    2359          49 : static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
    2360             : {
    2361          49 :     OGRErr ret = OGRERR_NONE;
    2362          49 :     OGRGeometry *g = pLayer->GetSpatialFilter();
    2363          49 :     *ppGeometry = g ? g->clone() : nullptr;
    2364          49 :     return ret;
    2365             : }
    2366             : 
    2367          67 : static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
    2368             : {
    2369          67 :     OGRErr ret = OGRERR_NONE;
    2370          67 :     int n = poDefn->GetFieldCount();
    2371          67 :     if (n > 0)
    2372             :     {
    2373          39 :         *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
    2374          39 :         if (!(*map))
    2375           0 :             return OGRERR_NOT_ENOUGH_MEMORY;
    2376         105 :         for (int i = 0; i < n; i++)
    2377          66 :             (*map)[i] = -1;
    2378             :     }
    2379          67 :     return ret;
    2380             : }
    2381             : 
    2382          38 : static OGRErr set_result_schema(OGRLayer *pLayerResult,
    2383             :                                 OGRFeatureDefn *poDefnInput,
    2384             :                                 OGRFeatureDefn *poDefnMethod, int *mapInput,
    2385             :                                 int *mapMethod, bool combined,
    2386             :                                 const char *const *papszOptions)
    2387             : {
    2388          38 :     OGRErr ret = OGRERR_NONE;
    2389          38 :     OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
    2390             :     const char *pszInputPrefix =
    2391          38 :         CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
    2392             :     const char *pszMethodPrefix =
    2393          38 :         CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
    2394             :     int bSkipFailures =
    2395          38 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    2396          38 :     if (poDefnResult->GetFieldCount() > 0)
    2397             :     {
    2398             :         // the user has defined the schema of the output layer
    2399           4 :         if (mapInput)
    2400             :         {
    2401           9 :             for (int iField = 0; iField < poDefnInput->GetFieldCount();
    2402             :                  iField++)
    2403             :             {
    2404             :                 CPLString osName(
    2405           5 :                     poDefnInput->GetFieldDefn(iField)->GetNameRef());
    2406           5 :                 if (pszInputPrefix != nullptr)
    2407           0 :                     osName = pszInputPrefix + osName;
    2408           5 :                 mapInput[iField] = poDefnResult->GetFieldIndex(osName);
    2409             :             }
    2410             :         }
    2411           4 :         if (!mapMethod)
    2412           2 :             return ret;
    2413             :         // cppcheck-suppress nullPointer
    2414           5 :         for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
    2415             :         {
    2416             :             // cppcheck-suppress nullPointer
    2417           3 :             CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
    2418           3 :             if (pszMethodPrefix != nullptr)
    2419           0 :                 osName = pszMethodPrefix + osName;
    2420           3 :             mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
    2421             :         }
    2422             :     }
    2423             :     else
    2424             :     {
    2425             :         // use schema from the input layer or from input and method layers
    2426          34 :         int nFieldsInput = poDefnInput->GetFieldCount();
    2427             : 
    2428             :         // If no prefix is specified and we have input+method layers, make
    2429             :         // sure we will generate unique field names
    2430          34 :         std::set<std::string> oSetInputFieldNames;
    2431          34 :         std::set<std::string> oSetMethodFieldNames;
    2432          34 :         if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
    2433             :             pszMethodPrefix == nullptr)
    2434             :         {
    2435          51 :             for (int iField = 0; iField < nFieldsInput; iField++)
    2436             :             {
    2437             :                 oSetInputFieldNames.insert(
    2438          24 :                     poDefnInput->GetFieldDefn(iField)->GetNameRef());
    2439             :             }
    2440          27 :             const int nFieldsMethod = poDefnMethod->GetFieldCount();
    2441          49 :             for (int iField = 0; iField < nFieldsMethod; iField++)
    2442             :             {
    2443             :                 oSetMethodFieldNames.insert(
    2444          22 :                     poDefnMethod->GetFieldDefn(iField)->GetNameRef());
    2445             :             }
    2446             :         }
    2447             : 
    2448          70 :         for (int iField = 0; iField < nFieldsInput; iField++)
    2449             :         {
    2450          36 :             OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
    2451          36 :             if (pszInputPrefix != nullptr)
    2452           0 :                 oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
    2453             :                                               oFieldDefn.GetNameRef()));
    2454          58 :             else if (!oSetMethodFieldNames.empty() &&
    2455          58 :                      oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
    2456          58 :                          oSetMethodFieldNames.end())
    2457             :             {
    2458             :                 // Field of same name present in method layer
    2459          13 :                 oFieldDefn.SetName(
    2460             :                     CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
    2461             :             }
    2462          36 :             ret = pLayerResult->CreateField(&oFieldDefn);
    2463          36 :             if (ret != OGRERR_NONE)
    2464             :             {
    2465           0 :                 if (!bSkipFailures)
    2466           0 :                     return ret;
    2467             :                 else
    2468             :                 {
    2469           0 :                     CPLErrorReset();
    2470           0 :                     ret = OGRERR_NONE;
    2471             :                 }
    2472             :             }
    2473          36 :             if (mapInput)
    2474          36 :                 mapInput[iField] = iField;
    2475             :         }
    2476          34 :         if (!combined)
    2477          11 :             return ret;
    2478          23 :         if (!mapMethod)
    2479          12 :             return ret;
    2480          11 :         if (!poDefnMethod)
    2481           0 :             return ret;
    2482          11 :         const int nFieldsMethod = poDefnMethod->GetFieldCount();
    2483          29 :         for (int iField = 0; iField < nFieldsMethod; iField++)
    2484             :         {
    2485          18 :             OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
    2486          18 :             if (pszMethodPrefix != nullptr)
    2487           0 :                 oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
    2488             :                                               oFieldDefn.GetNameRef()));
    2489          36 :             else if (!oSetInputFieldNames.empty() &&
    2490          36 :                      oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
    2491          36 :                          oSetInputFieldNames.end())
    2492             :             {
    2493             :                 // Field of same name present in method layer
    2494          11 :                 oFieldDefn.SetName(
    2495             :                     CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
    2496             :             }
    2497          18 :             ret = pLayerResult->CreateField(&oFieldDefn);
    2498          18 :             if (ret != OGRERR_NONE)
    2499             :             {
    2500           0 :                 if (!bSkipFailures)
    2501           0 :                     return ret;
    2502             :                 else
    2503             :                 {
    2504           0 :                     CPLErrorReset();
    2505           0 :                     ret = OGRERR_NONE;
    2506             :                 }
    2507             :             }
    2508          18 :             mapMethod[iField] = nFieldsInput + iField;
    2509             :         }
    2510             :     }
    2511          13 :     return ret;
    2512             : }
    2513             : 
    2514          90 : static OGRGeometry *set_filter_from(OGRLayer *pLayer,
    2515             :                                     OGRGeometry *pGeometryExistingFilter,
    2516             :                                     OGRFeature *pFeature)
    2517             : {
    2518          90 :     OGRGeometry *geom = pFeature->GetGeometryRef();
    2519          90 :     if (!geom)
    2520           0 :         return nullptr;
    2521          90 :     if (pGeometryExistingFilter)
    2522             :     {
    2523           0 :         if (!geom->Intersects(pGeometryExistingFilter))
    2524           0 :             return nullptr;
    2525           0 :         OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
    2526           0 :         if (intersection)
    2527             :         {
    2528           0 :             pLayer->SetSpatialFilter(intersection);
    2529           0 :             delete intersection;
    2530             :         }
    2531             :         else
    2532           0 :             return nullptr;
    2533             :     }
    2534             :     else
    2535             :     {
    2536          90 :         pLayer->SetSpatialFilter(geom);
    2537             :     }
    2538          90 :     return geom;
    2539             : }
    2540             : 
    2541          23 : static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
    2542             : {
    2543          23 :     OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    2544          23 :     if (eType == wkbPoint)
    2545           1 :         return OGRGeometryFactory::forceToMultiPoint(poGeom);
    2546          22 :     else if (eType == wkbPolygon)
    2547          22 :         return OGRGeometryFactory::forceToMultiPolygon(poGeom);
    2548           0 :     else if (eType == wkbLineString)
    2549           0 :         return OGRGeometryFactory::forceToMultiLineString(poGeom);
    2550             :     else
    2551           0 :         return poGeom;
    2552             : }
    2553             : 
    2554             : /************************************************************************/
    2555             : /*                          Intersection()                              */
    2556             : /************************************************************************/
    2557             : /**
    2558             :  * \brief Intersection of two layers.
    2559             :  *
    2560             :  * The result layer contains features whose geometries represent areas
    2561             :  * that are common between features in the input layer and in the
    2562             :  * method layer. The features in the result layer have attributes from
    2563             :  * both input and method layers. The schema of the result layer can be
    2564             :  * set by the user or, if it is empty, is initialized to contain all
    2565             :  * fields in the input and method layers.
    2566             :  *
    2567             :  * \note If the schema of the result is set by user and contains
    2568             :  * fields that have the same name as a field in input and in method
    2569             :  * layer, then the attribute in the result feature will get the value
    2570             :  * from the feature of the method layer.
    2571             :  *
    2572             :  * \note For best performance use the minimum amount of features in
    2573             :  * the method layer and copy it into a memory layer.
    2574             :  *
    2575             :  * \note This method relies on GEOS support. Do not use unless the
    2576             :  * GEOS support is compiled in.
    2577             :  *
    2578             :  * The recognized list of options is:
    2579             :  * <ul>
    2580             :  * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
    2581             :  *     feature could not be inserted or a GEOS call failed.
    2582             :  * </li>
    2583             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    2584             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    2585             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    2586             :  * </li>
    2587             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    2588             :  *     will be created from the fields of the input layer.
    2589             :  * </li>
    2590             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    2591             :  *     will be created from the fields of the method layer.
    2592             :  * </li>
    2593             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    2594             :  *     geometries to pretest intersection of features of method layer
    2595             :  *     with features of this layer.
    2596             :  * </li>
    2597             :  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
    2598             :  *     containment of features of method layer within the features of
    2599             :  *     this layer. This will speed up the method significantly in some
    2600             :  *     cases. Requires that the prepared geometries are in effect.
    2601             :  * </li>
    2602             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    2603             :  *     result features with lower dimension geometry that would
    2604             :  *     otherwise be added to the result layer. The default is YES, to add
    2605             :  *     features with lower dimension geometry, but only if the result layer
    2606             :  *     has an unknown geometry type.
    2607             :  * </li>
    2608             :  * </ul>
    2609             :  *
    2610             :  * This method is the same as the C function OGR_L_Intersection().
    2611             :  *
    2612             :  * @param pLayerMethod the method layer. Should not be NULL.
    2613             :  *
    2614             :  * @param pLayerResult the layer where the features resulting from the
    2615             :  * operation are inserted. Should not be NULL. See above the note
    2616             :  * about the schema.
    2617             :  *
    2618             :  * @param papszOptions NULL terminated list of options (may be NULL).
    2619             :  *
    2620             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    2621             :  * reporting progress or NULL.
    2622             :  *
    2623             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    2624             :  *
    2625             :  * @return an error code if there was an error or the execution was
    2626             :  * interrupted, OGRERR_NONE otherwise.
    2627             :  *
    2628             :  * @note The first geometry field is always used.
    2629             :  *
    2630             :  * @since OGR 1.10
    2631             :  */
    2632             : 
    2633           7 : OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    2634             :                               char **papszOptions, GDALProgressFunc pfnProgress,
    2635             :                               void *pProgressArg)
    2636             : {
    2637           7 :     OGRErr ret = OGRERR_NONE;
    2638           7 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    2639           7 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    2640           7 :     OGRFeatureDefn *poDefnResult = nullptr;
    2641           7 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    2642           7 :     int *mapInput = nullptr;
    2643           7 :     int *mapMethod = nullptr;
    2644           7 :     OGREnvelope sEnvelopeMethod;
    2645             :     GBool bEnvelopeSet;
    2646           7 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    2647           7 :     double progress_counter = 0;
    2648           7 :     double progress_ticker = 0;
    2649             :     const bool bSkipFailures =
    2650           7 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    2651           7 :     const bool bPromoteToMulti = CPLTestBool(
    2652             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    2653           7 :     const bool bUsePreparedGeometries = CPLTestBool(
    2654             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    2655           7 :     const bool bPretestContainment = CPLTestBool(
    2656             :         CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
    2657           7 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    2658             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    2659             : 
    2660             :     // check for GEOS
    2661           7 :     if (!OGRGeometryFactory::haveGEOS())
    2662             :     {
    2663           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2664             :                  "OGRLayer::Intersection() requires GEOS support");
    2665           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    2666             :     }
    2667             : 
    2668             :     // get resources
    2669           7 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    2670           7 :     if (ret != OGRERR_NONE)
    2671           0 :         goto done;
    2672           7 :     ret = create_field_map(poDefnInput, &mapInput);
    2673           7 :     if (ret != OGRERR_NONE)
    2674           0 :         goto done;
    2675           7 :     ret = create_field_map(poDefnMethod, &mapMethod);
    2676           7 :     if (ret != OGRERR_NONE)
    2677           0 :         goto done;
    2678           7 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    2679             :                             mapMethod, true, papszOptions);
    2680           7 :     if (ret != OGRERR_NONE)
    2681           0 :         goto done;
    2682           7 :     poDefnResult = pLayerResult->GetLayerDefn();
    2683           7 :     bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
    2684           7 :     if (bKeepLowerDimGeom)
    2685             :     {
    2686             :         // require that the result layer is of geom type unknown
    2687           5 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    2688             :         {
    2689           0 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    2690             :                             "since the result layer does not allow it.");
    2691           0 :             bKeepLowerDimGeom = false;
    2692             :         }
    2693             :     }
    2694             : 
    2695          20 :     for (auto &&x : this)
    2696             :     {
    2697             : 
    2698          13 :         if (pfnProgress)
    2699             :         {
    2700           2 :             double p = progress_counter / progress_max;
    2701           2 :             if (p > progress_ticker)
    2702             :             {
    2703           1 :                 if (!pfnProgress(p, "", pProgressArg))
    2704             :                 {
    2705           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    2706           0 :                     ret = OGRERR_FAILURE;
    2707           0 :                     goto done;
    2708             :                 }
    2709             :             }
    2710           2 :             progress_counter += 1.0;
    2711             :         }
    2712             : 
    2713             :         // is it worth to proceed?
    2714          13 :         if (bEnvelopeSet)
    2715             :         {
    2716          13 :             OGRGeometry *x_geom = x->GetGeometryRef();
    2717          13 :             if (x_geom)
    2718             :             {
    2719          13 :                 OGREnvelope x_env;
    2720          13 :                 x_geom->getEnvelope(&x_env);
    2721          13 :                 if (x_env.MaxX < sEnvelopeMethod.MinX ||
    2722          13 :                     x_env.MaxY < sEnvelopeMethod.MinY ||
    2723          13 :                     sEnvelopeMethod.MaxX < x_env.MinX ||
    2724          13 :                     sEnvelopeMethod.MaxY < x_env.MinY)
    2725             :                 {
    2726           0 :                     continue;
    2727             :                 }
    2728             :             }
    2729             :             else
    2730             :             {
    2731           0 :                 continue;
    2732             :             }
    2733             :         }
    2734             : 
    2735             :         // set up the filter for method layer
    2736          13 :         CPLErrorReset();
    2737             :         OGRGeometry *x_geom =
    2738          13 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    2739          13 :         if (CPLGetLastErrorType() != CE_None)
    2740             :         {
    2741           0 :             if (!bSkipFailures)
    2742             :             {
    2743           0 :                 ret = OGRERR_FAILURE;
    2744           0 :                 goto done;
    2745             :             }
    2746             :             else
    2747             :             {
    2748           0 :                 CPLErrorReset();
    2749           0 :                 ret = OGRERR_NONE;
    2750             :             }
    2751             :         }
    2752          13 :         if (!x_geom)
    2753             :         {
    2754           0 :             continue;
    2755             :         }
    2756             : 
    2757           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    2758          13 :         if (bUsePreparedGeometries)
    2759             :         {
    2760          13 :             x_prepared_geom.reset(
    2761             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    2762          13 :             if (!x_prepared_geom)
    2763             :             {
    2764           0 :                 goto done;
    2765             :             }
    2766             :         }
    2767             : 
    2768          28 :         for (auto &&y : pLayerMethod)
    2769             :         {
    2770          15 :             OGRGeometry *y_geom = y->GetGeometryRef();
    2771          15 :             if (!y_geom)
    2772           4 :                 continue;
    2773           0 :             OGRGeometryUniquePtr z_geom;
    2774             : 
    2775          15 :             if (x_prepared_geom)
    2776             :             {
    2777          15 :                 CPLErrorReset();
    2778          15 :                 ret = OGRERR_NONE;
    2779          15 :                 if (bPretestContainment &&
    2780           0 :                     OGRPreparedGeometryContains(x_prepared_geom.get(),
    2781             :                                                 OGRGeometry::ToHandle(y_geom)))
    2782             :                 {
    2783           0 :                     if (CPLGetLastErrorType() == CE_None)
    2784           0 :                         z_geom.reset(y_geom->clone());
    2785             :                 }
    2786          15 :                 else if (!(OGRPreparedGeometryIntersects(
    2787             :                              x_prepared_geom.get(),
    2788             :                              OGRGeometry::ToHandle(y_geom))))
    2789             :                 {
    2790           0 :                     if (CPLGetLastErrorType() == CE_None)
    2791             :                     {
    2792           0 :                         continue;
    2793             :                     }
    2794             :                 }
    2795          15 :                 if (CPLGetLastErrorType() != CE_None)
    2796             :                 {
    2797           0 :                     if (!bSkipFailures)
    2798             :                     {
    2799           0 :                         ret = OGRERR_FAILURE;
    2800           0 :                         goto done;
    2801             :                     }
    2802             :                     else
    2803             :                     {
    2804           0 :                         CPLErrorReset();
    2805           0 :                         ret = OGRERR_NONE;
    2806           0 :                         continue;
    2807             :                     }
    2808             :                 }
    2809             :             }
    2810          15 :             if (!z_geom)
    2811             :             {
    2812          15 :                 CPLErrorReset();
    2813          15 :                 z_geom.reset(x_geom->Intersection(y_geom));
    2814          15 :                 if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
    2815             :                 {
    2816           0 :                     if (!bSkipFailures)
    2817             :                     {
    2818           0 :                         ret = OGRERR_FAILURE;
    2819           0 :                         goto done;
    2820             :                     }
    2821             :                     else
    2822             :                     {
    2823           0 :                         CPLErrorReset();
    2824           0 :                         ret = OGRERR_NONE;
    2825           0 :                         continue;
    2826             :                     }
    2827             :                 }
    2828          30 :                 if (z_geom->IsEmpty() ||
    2829          15 :                     (!bKeepLowerDimGeom &&
    2830           6 :                      (x_geom->getDimension() == y_geom->getDimension() &&
    2831           6 :                       z_geom->getDimension() < x_geom->getDimension())))
    2832             :                 {
    2833           4 :                     continue;
    2834             :                 }
    2835             :             }
    2836          11 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    2837          11 :             z->SetFieldsFrom(x.get(), mapInput);
    2838          11 :             z->SetFieldsFrom(y.get(), mapMethod);
    2839          11 :             if (bPromoteToMulti)
    2840           3 :                 z_geom.reset(promote_to_multi(z_geom.release()));
    2841          11 :             z->SetGeometryDirectly(z_geom.release());
    2842          11 :             ret = pLayerResult->CreateFeature(z.get());
    2843             : 
    2844          11 :             if (ret != OGRERR_NONE)
    2845             :             {
    2846           0 :                 if (!bSkipFailures)
    2847             :                 {
    2848           0 :                     goto done;
    2849             :                 }
    2850             :                 else
    2851             :                 {
    2852           0 :                     CPLErrorReset();
    2853           0 :                     ret = OGRERR_NONE;
    2854             :                 }
    2855             :             }
    2856             :         }
    2857             :     }
    2858           7 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    2859             :     {
    2860           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    2861           0 :         ret = OGRERR_FAILURE;
    2862           0 :         goto done;
    2863             :     }
    2864           7 : done:
    2865             :     // release resources
    2866           7 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    2867           7 :     if (pGeometryMethodFilter)
    2868           0 :         delete pGeometryMethodFilter;
    2869           7 :     if (mapInput)
    2870           3 :         VSIFree(mapInput);
    2871           7 :     if (mapMethod)
    2872           3 :         VSIFree(mapMethod);
    2873           7 :     return ret;
    2874             : }
    2875             : 
    2876             : /************************************************************************/
    2877             : /*                       OGR_L_Intersection()                           */
    2878             : /************************************************************************/
    2879             : /**
    2880             :  * \brief Intersection of two layers.
    2881             :  *
    2882             :  * The result layer contains features whose geometries represent areas
    2883             :  * that are common between features in the input layer and in the
    2884             :  * method layer. The features in the result layer have attributes from
    2885             :  * both input and method layers. The schema of the result layer can be
    2886             :  * set by the user or, if it is empty, is initialized to contain all
    2887             :  * fields in the input and method layers.
    2888             :  *
    2889             :  * \note If the schema of the result is set by user and contains
    2890             :  * fields that have the same name as a field in input and in method
    2891             :  * layer, then the attribute in the result feature will get the value
    2892             :  * from the feature of the method layer.
    2893             :  *
    2894             :  * \note For best performance use the minimum amount of features in
    2895             :  * the method layer and copy it into a memory layer.
    2896             :  *
    2897             :  * \note This method relies on GEOS support. Do not use unless the
    2898             :  * GEOS support is compiled in.
    2899             :  *
    2900             :  * The recognized list of options is :
    2901             :  * <ul>
    2902             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    2903             :  *     feature could not be inserted or a GEOS call failed.
    2904             :  * </li>
    2905             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    2906             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    2907             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    2908             :  * </li>
    2909             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    2910             :  *     will be created from the fields of the input layer.
    2911             :  * </li>
    2912             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    2913             :  *     will be created from the fields of the method layer.
    2914             :  * </li>
    2915             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    2916             :  *     geometries to pretest intersection of features of method layer
    2917             :  *     with features of this layer.
    2918             :  * </li>
    2919             :  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
    2920             :  *     containment of features of method layer within the features of
    2921             :  *     this layer. This will speed up the method significantly in some
    2922             :  *     cases. Requires that the prepared geometries are in effect.
    2923             :  * </li>
    2924             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    2925             :  *     result features with lower dimension geometry that would
    2926             :  *     otherwise be added to the result layer. The default is YES, to add
    2927             :  *     features with lower dimension geometry, but only if the result layer
    2928             :  *     has an unknown geometry type.
    2929             :  * </li>
    2930             :  * </ul>
    2931             :  *
    2932             :  * This function is the same as the C++ method OGRLayer::Intersection().
    2933             :  *
    2934             :  * @param pLayerInput the input layer. Should not be NULL.
    2935             :  *
    2936             :  * @param pLayerMethod the method layer. Should not be NULL.
    2937             :  *
    2938             :  * @param pLayerResult the layer where the features resulting from the
    2939             :  * operation are inserted. Should not be NULL. See above the note
    2940             :  * about the schema.
    2941             :  *
    2942             :  * @param papszOptions NULL terminated list of options (may be NULL).
    2943             :  *
    2944             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    2945             :  * reporting progress or NULL.
    2946             :  *
    2947             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    2948             :  *
    2949             :  * @return an error code if there was an error or the execution was
    2950             :  * interrupted, OGRERR_NONE otherwise.
    2951             :  *
    2952             :  * @note The first geometry field is always used.
    2953             :  *
    2954             :  * @since OGR 1.10
    2955             :  */
    2956             : 
    2957           7 : OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    2958             :                           OGRLayerH pLayerResult, char **papszOptions,
    2959             :                           GDALProgressFunc pfnProgress, void *pProgressArg)
    2960             : 
    2961             : {
    2962           7 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
    2963           7 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
    2964             :                       OGRERR_INVALID_HANDLE);
    2965           7 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
    2966             :                       OGRERR_INVALID_HANDLE);
    2967             : 
    2968             :     return OGRLayer::FromHandle(pLayerInput)
    2969           7 :         ->Intersection(OGRLayer::FromHandle(pLayerMethod),
    2970             :                        OGRLayer::FromHandle(pLayerResult), papszOptions,
    2971           7 :                        pfnProgress, pProgressArg);
    2972             : }
    2973             : 
    2974             : /************************************************************************/
    2975             : /*                              Union()                                 */
    2976             : /************************************************************************/
    2977             : 
    2978             : /**
    2979             :  * \brief Union of two layers.
    2980             :  *
    2981             :  * The result layer contains features whose geometries represent areas
    2982             :  * that are either in the input layer, in the method layer, or in
    2983             :  * both. The features in the result layer have attributes from both
    2984             :  * input and method layers. For features which represent areas that
    2985             :  * are only in the input or in the method layer the respective
    2986             :  * attributes have undefined values. The schema of the result layer
    2987             :  * can be set by the user or, if it is empty, is initialized to
    2988             :  * contain all fields in the input and method layers.
    2989             :  *
    2990             :  * \note If the schema of the result is set by user and contains
    2991             :  * fields that have the same name as a field in input and in method
    2992             :  * layer, then the attribute in the result feature will get the value
    2993             :  * from the feature of the method layer (even if it is undefined).
    2994             :  *
    2995             :  * \note For best performance use the minimum amount of features in
    2996             :  * the method layer and copy it into a memory layer.
    2997             :  *
    2998             :  * \note This method relies on GEOS support. Do not use unless the
    2999             :  * GEOS support is compiled in.
    3000             :  *
    3001             :  * The recognized list of options is :
    3002             :  * <ul>
    3003             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    3004             :  *     feature could not be inserted or a GEOS call failed.
    3005             :  * </li>
    3006             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    3007             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    3008             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    3009             :  * </li>
    3010             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3011             :  *     will be created from the fields of the input layer.
    3012             :  * </li>
    3013             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3014             :  *     will be created from the fields of the method layer.
    3015             :  * </li>
    3016             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    3017             :  *     geometries to pretest intersection of features of method layer
    3018             :  *     with features of this layer.
    3019             :  * </li>
    3020             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    3021             :  *     result features with lower dimension geometry that would
    3022             :  *     otherwise be added to the result layer. The default is YES, to add
    3023             :  *     features with lower dimension geometry, but only if the result layer
    3024             :  *     has an unknown geometry type.
    3025             :  * </li>
    3026             :  * </ul>
    3027             :  *
    3028             :  * This method is the same as the C function OGR_L_Union().
    3029             :  *
    3030             :  * @param pLayerMethod the method layer. Should not be NULL.
    3031             :  *
    3032             :  * @param pLayerResult the layer where the features resulting from the
    3033             :  * operation are inserted. Should not be NULL. See above the note
    3034             :  * about the schema.
    3035             :  *
    3036             :  * @param papszOptions NULL terminated list of options (may be NULL).
    3037             :  *
    3038             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    3039             :  * reporting progress or NULL.
    3040             :  *
    3041             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    3042             :  *
    3043             :  * @return an error code if there was an error or the execution was
    3044             :  * interrupted, OGRERR_NONE otherwise.
    3045             :  *
    3046             :  * @note The first geometry field is always used.
    3047             :  *
    3048             :  * @since OGR 1.10
    3049             :  */
    3050             : 
    3051           7 : OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    3052             :                        char **papszOptions, GDALProgressFunc pfnProgress,
    3053             :                        void *pProgressArg)
    3054             : {
    3055           7 :     OGRErr ret = OGRERR_NONE;
    3056           7 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    3057           7 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    3058           7 :     OGRFeatureDefn *poDefnResult = nullptr;
    3059           7 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    3060           7 :     OGRGeometry *pGeometryInputFilter = nullptr;
    3061           7 :     int *mapInput = nullptr;
    3062           7 :     int *mapMethod = nullptr;
    3063             :     double progress_max =
    3064           7 :         static_cast<double>(GetFeatureCount(FALSE)) +
    3065           7 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    3066           7 :     double progress_counter = 0;
    3067           7 :     double progress_ticker = 0;
    3068             :     const bool bSkipFailures =
    3069           7 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    3070           7 :     const bool bPromoteToMulti = CPLTestBool(
    3071             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    3072           7 :     const bool bUsePreparedGeometries = CPLTestBool(
    3073             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    3074           7 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    3075             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    3076             : 
    3077             :     // check for GEOS
    3078           7 :     if (!OGRGeometryFactory::haveGEOS())
    3079             :     {
    3080           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3081             :                  "OGRLayer::Union() requires GEOS support");
    3082           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    3083             :     }
    3084             : 
    3085             :     // get resources
    3086           7 :     ret = clone_spatial_filter(this, &pGeometryInputFilter);
    3087           7 :     if (ret != OGRERR_NONE)
    3088           0 :         goto done;
    3089           7 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    3090           7 :     if (ret != OGRERR_NONE)
    3091           0 :         goto done;
    3092           7 :     ret = create_field_map(poDefnInput, &mapInput);
    3093           7 :     if (ret != OGRERR_NONE)
    3094           0 :         goto done;
    3095           7 :     ret = create_field_map(poDefnMethod, &mapMethod);
    3096           7 :     if (ret != OGRERR_NONE)
    3097           0 :         goto done;
    3098           7 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    3099             :                             mapMethod, true, papszOptions);
    3100           7 :     if (ret != OGRERR_NONE)
    3101           0 :         goto done;
    3102           7 :     poDefnResult = pLayerResult->GetLayerDefn();
    3103           7 :     if (bKeepLowerDimGeom)
    3104             :     {
    3105             :         // require that the result layer is of geom type unknown
    3106           5 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    3107             :         {
    3108           0 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    3109             :                             "since the result layer does not allow it.");
    3110           0 :             bKeepLowerDimGeom = FALSE;
    3111             :         }
    3112             :     }
    3113             : 
    3114             :     // add features based on input layer
    3115          20 :     for (auto &&x : this)
    3116             :     {
    3117             : 
    3118          13 :         if (pfnProgress)
    3119             :         {
    3120           2 :             double p = progress_counter / progress_max;
    3121           2 :             if (p > progress_ticker)
    3122             :             {
    3123           1 :                 if (!pfnProgress(p, "", pProgressArg))
    3124             :                 {
    3125           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3126           0 :                     ret = OGRERR_FAILURE;
    3127           0 :                     goto done;
    3128             :                 }
    3129             :             }
    3130           2 :             progress_counter += 1.0;
    3131             :         }
    3132             : 
    3133             :         // set up the filter on method layer
    3134          13 :         CPLErrorReset();
    3135             :         OGRGeometry *x_geom =
    3136          13 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    3137          13 :         if (CPLGetLastErrorType() != CE_None)
    3138             :         {
    3139           0 :             if (!bSkipFailures)
    3140             :             {
    3141           0 :                 ret = OGRERR_FAILURE;
    3142           0 :                 goto done;
    3143             :             }
    3144             :             else
    3145             :             {
    3146           0 :                 CPLErrorReset();
    3147           0 :                 ret = OGRERR_NONE;
    3148             :             }
    3149             :         }
    3150          13 :         if (!x_geom)
    3151             :         {
    3152           0 :             continue;
    3153             :         }
    3154             : 
    3155           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    3156          13 :         if (bUsePreparedGeometries)
    3157             :         {
    3158          13 :             x_prepared_geom.reset(
    3159             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    3160          13 :             if (!x_prepared_geom)
    3161             :             {
    3162           0 :                 goto done;
    3163             :             }
    3164             :         }
    3165             : 
    3166             :         OGRGeometryUniquePtr x_geom_diff(
    3167             :             x_geom
    3168          13 :                 ->clone());  // this will be the geometry of the result feature
    3169          28 :         for (auto &&y : pLayerMethod)
    3170             :         {
    3171          15 :             OGRGeometry *y_geom = y->GetGeometryRef();
    3172          15 :             if (!y_geom)
    3173             :             {
    3174           0 :                 continue;
    3175             :             }
    3176             : 
    3177          15 :             CPLErrorReset();
    3178          30 :             if (x_prepared_geom &&
    3179          15 :                 !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
    3180          15 :                                                 OGRGeometry::ToHandle(y_geom))))
    3181             :             {
    3182           0 :                 if (CPLGetLastErrorType() == CE_None)
    3183             :                 {
    3184           0 :                     continue;
    3185             :                 }
    3186             :             }
    3187          15 :             if (CPLGetLastErrorType() != CE_None)
    3188             :             {
    3189           0 :                 if (!bSkipFailures)
    3190             :                 {
    3191           0 :                     ret = OGRERR_FAILURE;
    3192           0 :                     goto done;
    3193             :                 }
    3194             :                 else
    3195             :                 {
    3196           0 :                     CPLErrorReset();
    3197           0 :                     ret = OGRERR_NONE;
    3198             :                 }
    3199             :             }
    3200             : 
    3201          15 :             CPLErrorReset();
    3202          15 :             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
    3203          15 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    3204             :             {
    3205           0 :                 if (!bSkipFailures)
    3206             :                 {
    3207           0 :                     ret = OGRERR_FAILURE;
    3208           0 :                     goto done;
    3209             :                 }
    3210             :                 else
    3211             :                 {
    3212           0 :                     CPLErrorReset();
    3213           0 :                     ret = OGRERR_NONE;
    3214           0 :                     continue;
    3215             :                 }
    3216             :             }
    3217          30 :             if (poIntersection->IsEmpty() ||
    3218          15 :                 (!bKeepLowerDimGeom &&
    3219           6 :                  (x_geom->getDimension() == y_geom->getDimension() &&
    3220           6 :                   poIntersection->getDimension() < x_geom->getDimension())))
    3221             :             {
    3222             :                 // ok
    3223             :             }
    3224             :             else
    3225             :             {
    3226          11 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3227          11 :                 z->SetFieldsFrom(x.get(), mapInput);
    3228          11 :                 z->SetFieldsFrom(y.get(), mapMethod);
    3229          11 :                 if (bPromoteToMulti)
    3230           2 :                     poIntersection.reset(
    3231             :                         promote_to_multi(poIntersection.release()));
    3232          11 :                 z->SetGeometryDirectly(poIntersection.release());
    3233             : 
    3234          11 :                 if (x_geom_diff)
    3235             :                 {
    3236          11 :                     CPLErrorReset();
    3237             :                     OGRGeometryUniquePtr x_geom_diff_new(
    3238          11 :                         x_geom_diff->Difference(y_geom));
    3239          22 :                     if (CPLGetLastErrorType() != CE_None ||
    3240          11 :                         x_geom_diff_new == nullptr)
    3241             :                     {
    3242           0 :                         if (!bSkipFailures)
    3243             :                         {
    3244           0 :                             ret = OGRERR_FAILURE;
    3245           0 :                             goto done;
    3246             :                         }
    3247             :                         else
    3248             :                         {
    3249           0 :                             CPLErrorReset();
    3250             :                         }
    3251             :                     }
    3252             :                     else
    3253             :                     {
    3254          11 :                         x_geom_diff.swap(x_geom_diff_new);
    3255             :                     }
    3256             :                 }
    3257             : 
    3258          11 :                 ret = pLayerResult->CreateFeature(z.get());
    3259          11 :                 if (ret != OGRERR_NONE)
    3260             :                 {
    3261           0 :                     if (!bSkipFailures)
    3262             :                     {
    3263           0 :                         goto done;
    3264             :                     }
    3265             :                     else
    3266             :                     {
    3267           0 :                         CPLErrorReset();
    3268           0 :                         ret = OGRERR_NONE;
    3269             :                     }
    3270             :                 }
    3271             :             }
    3272             :         }
    3273          13 :         x_prepared_geom.reset();
    3274             : 
    3275          13 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    3276             :         {
    3277             :             // ok
    3278             :         }
    3279             :         else
    3280             :         {
    3281          11 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3282          11 :             z->SetFieldsFrom(x.get(), mapInput);
    3283          11 :             if (bPromoteToMulti)
    3284           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    3285          11 :             z->SetGeometryDirectly(x_geom_diff.release());
    3286          11 :             ret = pLayerResult->CreateFeature(z.get());
    3287          11 :             if (ret != OGRERR_NONE)
    3288             :             {
    3289           0 :                 if (!bSkipFailures)
    3290             :                 {
    3291           0 :                     goto done;
    3292             :                 }
    3293             :                 else
    3294             :                 {
    3295           0 :                     CPLErrorReset();
    3296           0 :                     ret = OGRERR_NONE;
    3297             :                 }
    3298             :             }
    3299             :         }
    3300             :     }
    3301             : 
    3302             :     // restore filter on method layer and add features based on it
    3303           7 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    3304          17 :     for (auto &&x : pLayerMethod)
    3305             :     {
    3306             : 
    3307          10 :         if (pfnProgress)
    3308             :         {
    3309           1 :             double p = progress_counter / progress_max;
    3310           1 :             if (p > progress_ticker)
    3311             :             {
    3312           1 :                 if (!pfnProgress(p, "", pProgressArg))
    3313             :                 {
    3314           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3315           0 :                     ret = OGRERR_FAILURE;
    3316           0 :                     goto done;
    3317             :                 }
    3318             :             }
    3319           1 :             progress_counter += 1.0;
    3320             :         }
    3321             : 
    3322             :         // set up the filter on input layer
    3323          10 :         CPLErrorReset();
    3324             :         OGRGeometry *x_geom =
    3325          10 :             set_filter_from(this, pGeometryInputFilter, x.get());
    3326          10 :         if (CPLGetLastErrorType() != CE_None)
    3327             :         {
    3328           0 :             if (!bSkipFailures)
    3329             :             {
    3330           0 :                 ret = OGRERR_FAILURE;
    3331           0 :                 goto done;
    3332             :             }
    3333             :             else
    3334             :             {
    3335           0 :                 CPLErrorReset();
    3336           0 :                 ret = OGRERR_NONE;
    3337             :             }
    3338             :         }
    3339          10 :         if (!x_geom)
    3340             :         {
    3341           0 :             continue;
    3342             :         }
    3343             : 
    3344             :         OGRGeometryUniquePtr x_geom_diff(
    3345             :             x_geom
    3346          10 :                 ->clone());  // this will be the geometry of the result feature
    3347          25 :         for (auto &&y : this)
    3348             :         {
    3349          15 :             OGRGeometry *y_geom = y->GetGeometryRef();
    3350          15 :             if (!y_geom)
    3351             :             {
    3352           0 :                 continue;
    3353             :             }
    3354             : 
    3355          15 :             if (x_geom_diff)
    3356             :             {
    3357          15 :                 CPLErrorReset();
    3358             :                 OGRGeometryUniquePtr x_geom_diff_new(
    3359          15 :                     x_geom_diff->Difference(y_geom));
    3360          30 :                 if (CPLGetLastErrorType() != CE_None ||
    3361          15 :                     x_geom_diff_new == nullptr)
    3362             :                 {
    3363           0 :                     if (!bSkipFailures)
    3364             :                     {
    3365           0 :                         ret = OGRERR_FAILURE;
    3366           0 :                         goto done;
    3367             :                     }
    3368             :                     else
    3369             :                     {
    3370           0 :                         CPLErrorReset();
    3371           0 :                         ret = OGRERR_NONE;
    3372             :                     }
    3373             :                 }
    3374             :                 else
    3375             :                 {
    3376          15 :                     x_geom_diff.swap(x_geom_diff_new);
    3377             :                 }
    3378             :             }
    3379             :         }
    3380             : 
    3381          10 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    3382             :         {
    3383             :             // ok
    3384             :         }
    3385             :         else
    3386             :         {
    3387           7 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3388           7 :             z->SetFieldsFrom(x.get(), mapMethod);
    3389           7 :             if (bPromoteToMulti)
    3390           1 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    3391           7 :             z->SetGeometryDirectly(x_geom_diff.release());
    3392           7 :             ret = pLayerResult->CreateFeature(z.get());
    3393           7 :             if (ret != OGRERR_NONE)
    3394             :             {
    3395           0 :                 if (!bSkipFailures)
    3396             :                 {
    3397           0 :                     goto done;
    3398             :                 }
    3399             :                 else
    3400             :                 {
    3401           0 :                     CPLErrorReset();
    3402           0 :                     ret = OGRERR_NONE;
    3403             :                 }
    3404             :             }
    3405             :         }
    3406             :     }
    3407           7 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    3408             :     {
    3409           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3410           0 :         ret = OGRERR_FAILURE;
    3411           0 :         goto done;
    3412             :     }
    3413           7 : done:
    3414             :     // release resources
    3415           7 :     SetSpatialFilter(pGeometryInputFilter);
    3416           7 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    3417           7 :     if (pGeometryMethodFilter)
    3418           0 :         delete pGeometryMethodFilter;
    3419           7 :     if (pGeometryInputFilter)
    3420           0 :         delete pGeometryInputFilter;
    3421           7 :     if (mapInput)
    3422           4 :         VSIFree(mapInput);
    3423           7 :     if (mapMethod)
    3424           3 :         VSIFree(mapMethod);
    3425           7 :     return ret;
    3426             : }
    3427             : 
    3428             : /************************************************************************/
    3429             : /*                           OGR_L_Union()                              */
    3430             : /************************************************************************/
    3431             : 
    3432             : /**
    3433             :  * \brief Union of two layers.
    3434             :  *
    3435             :  * The result layer contains features whose geometries represent areas
    3436             :  * that are in either in the input layer, in the method layer, or in
    3437             :  * both. The features in the result layer have attributes from both
    3438             :  * input and method layers. For features which represent areas that
    3439             :  * are only in the input or in the method layer the respective
    3440             :  * attributes have undefined values. The schema of the result layer
    3441             :  * can be set by the user or, if it is empty, is initialized to
    3442             :  * contain all fields in the input and method layers.
    3443             :  *
    3444             :  * \note If the schema of the result is set by user and contains
    3445             :  * fields that have the same name as a field in input and in method
    3446             :  * layer, then the attribute in the result feature will get the value
    3447             :  * from the feature of the method layer (even if it is undefined).
    3448             :  *
    3449             :  * \note For best performance use the minimum amount of features in
    3450             :  * the method layer and copy it into a memory layer.
    3451             :  *
    3452             :  * \note This method relies on GEOS support. Do not use unless the
    3453             :  * GEOS support is compiled in.
    3454             :  *
    3455             :  * The recognized list of options is :
    3456             :  * <ul>
    3457             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    3458             :  *     feature could not be inserted or a GEOS call failed.
    3459             :  * </li>
    3460             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    3461             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    3462             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    3463             :  * </li>
    3464             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3465             :  *     will be created from the fields of the input layer.
    3466             :  * </li>
    3467             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3468             :  *     will be created from the fields of the method layer.
    3469             :  * </li>
    3470             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    3471             :  *     geometries to pretest intersection of features of method layer
    3472             :  *     with features of this layer.
    3473             :  * </li>
    3474             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    3475             :  *     result features with lower dimension geometry that would
    3476             :  *     otherwise be added to the result layer. The default is YES, to add
    3477             :  *     features with lower dimension geometry, but only if the result layer
    3478             :  *     has an unknown geometry type.
    3479             :  * </li>
    3480             :  * </ul>
    3481             :  *
    3482             :  * This function is the same as the C++ method OGRLayer::Union().
    3483             :  *
    3484             :  * @param pLayerInput the input layer. Should not be NULL.
    3485             :  *
    3486             :  * @param pLayerMethod the method layer. Should not be NULL.
    3487             :  *
    3488             :  * @param pLayerResult the layer where the features resulting from the
    3489             :  * operation are inserted. Should not be NULL. See above the note
    3490             :  * about the schema.
    3491             :  *
    3492             :  * @param papszOptions NULL terminated list of options (may be NULL).
    3493             :  *
    3494             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    3495             :  * reporting progress or NULL.
    3496             :  *
    3497             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    3498             :  *
    3499             :  * @return an error code if there was an error or the execution was
    3500             :  * interrupted, OGRERR_NONE otherwise.
    3501             :  *
    3502             :  * @note The first geometry field is always used.
    3503             :  *
    3504             :  * @since OGR 1.10
    3505             :  */
    3506             : 
    3507           7 : OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    3508             :                    OGRLayerH pLayerResult, char **papszOptions,
    3509             :                    GDALProgressFunc pfnProgress, void *pProgressArg)
    3510             : 
    3511             : {
    3512           7 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    3513           7 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    3514           7 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
    3515             : 
    3516             :     return OGRLayer::FromHandle(pLayerInput)
    3517           7 :         ->Union(OGRLayer::FromHandle(pLayerMethod),
    3518             :                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    3519           7 :                 pProgressArg);
    3520             : }
    3521             : 
    3522             : /************************************************************************/
    3523             : /*                          SymDifference()                             */
    3524             : /************************************************************************/
    3525             : 
    3526             : /**
    3527             :  * \brief Symmetrical difference of two layers.
    3528             :  *
    3529             :  * The result layer contains features whose geometries represent areas
    3530             :  * that are in either in the input layer or in the method layer but
    3531             :  * not in both. The features in the result layer have attributes from
    3532             :  * both input and method layers. For features which represent areas
    3533             :  * that are only in the input or in the method layer the respective
    3534             :  * attributes have undefined values. The schema of the result layer
    3535             :  * can be set by the user or, if it is empty, is initialized to
    3536             :  * contain all fields in the input and method layers.
    3537             :  *
    3538             :  * \note If the schema of the result is set by user and contains
    3539             :  * fields that have the same name as a field in input and in method
    3540             :  * layer, then the attribute in the result feature will get the value
    3541             :  * from the feature of the method layer (even if it is undefined).
    3542             :  *
    3543             :  * \note For best performance use the minimum amount of features in
    3544             :  * the method layer and copy it into a memory layer.
    3545             :  *
    3546             :  * \note This method relies on GEOS support. Do not use unless the
    3547             :  * GEOS support is compiled in.
    3548             :  *
    3549             :  * The recognized list of options is :
    3550             :  * <ul>
    3551             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    3552             :  *     feature could not be inserted or a GEOS call failed.
    3553             :  * </li>
    3554             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
    3555             :  *     into MultiPolygons, or LineStrings to MultiLineStrings.
    3556             :  * </li>
    3557             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3558             :  *     will be created from the fields of the input layer.
    3559             :  * </li>
    3560             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3561             :  *     will be created from the fields of the method layer.
    3562             :  * </li>
    3563             :  * </ul>
    3564             :  *
    3565             :  * This method is the same as the C function OGR_L_SymDifference().
    3566             :  *
    3567             :  * @param pLayerMethod the method layer. Should not be NULL.
    3568             :  *
    3569             :  * @param pLayerResult the layer where the features resulting from the
    3570             :  * operation are inserted. Should not be NULL. See above the note
    3571             :  * about the schema.
    3572             :  *
    3573             :  * @param papszOptions NULL terminated list of options (may be NULL).
    3574             :  *
    3575             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    3576             :  * reporting progress or NULL.
    3577             :  *
    3578             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    3579             :  *
    3580             :  * @return an error code if there was an error or the execution was
    3581             :  * interrupted, OGRERR_NONE otherwise.
    3582             :  *
    3583             :  * @note The first geometry field is always used.
    3584             :  *
    3585             :  * @since OGR 1.10
    3586             :  */
    3587             : 
    3588           4 : OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    3589             :                                char **papszOptions,
    3590             :                                GDALProgressFunc pfnProgress, void *pProgressArg)
    3591             : {
    3592           4 :     OGRErr ret = OGRERR_NONE;
    3593           4 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    3594           4 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    3595           4 :     OGRFeatureDefn *poDefnResult = nullptr;
    3596           4 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    3597           4 :     OGRGeometry *pGeometryInputFilter = nullptr;
    3598           4 :     int *mapInput = nullptr;
    3599           4 :     int *mapMethod = nullptr;
    3600             :     double progress_max =
    3601           4 :         static_cast<double>(GetFeatureCount(FALSE)) +
    3602           4 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    3603           4 :     double progress_counter = 0;
    3604           4 :     double progress_ticker = 0;
    3605             :     const bool bSkipFailures =
    3606           4 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    3607           4 :     const bool bPromoteToMulti = CPLTestBool(
    3608             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    3609             : 
    3610             :     // check for GEOS
    3611           4 :     if (!OGRGeometryFactory::haveGEOS())
    3612             :     {
    3613           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3614             :                  "OGRLayer::SymDifference() requires GEOS support");
    3615           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    3616             :     }
    3617             : 
    3618             :     // get resources
    3619           4 :     ret = clone_spatial_filter(this, &pGeometryInputFilter);
    3620           4 :     if (ret != OGRERR_NONE)
    3621           0 :         goto done;
    3622           4 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    3623           4 :     if (ret != OGRERR_NONE)
    3624           0 :         goto done;
    3625           4 :     ret = create_field_map(poDefnInput, &mapInput);
    3626           4 :     if (ret != OGRERR_NONE)
    3627           0 :         goto done;
    3628           4 :     ret = create_field_map(poDefnMethod, &mapMethod);
    3629           4 :     if (ret != OGRERR_NONE)
    3630           0 :         goto done;
    3631           4 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    3632             :                             mapMethod, true, papszOptions);
    3633           4 :     if (ret != OGRERR_NONE)
    3634           0 :         goto done;
    3635           4 :     poDefnResult = pLayerResult->GetLayerDefn();
    3636             : 
    3637             :     // add features based on input layer
    3638          12 :     for (auto &&x : this)
    3639             :     {
    3640             : 
    3641           8 :         if (pfnProgress)
    3642             :         {
    3643           2 :             double p = progress_counter / progress_max;
    3644           2 :             if (p > progress_ticker)
    3645             :             {
    3646           1 :                 if (!pfnProgress(p, "", pProgressArg))
    3647             :                 {
    3648           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3649           0 :                     ret = OGRERR_FAILURE;
    3650           0 :                     goto done;
    3651             :                 }
    3652             :             }
    3653           2 :             progress_counter += 1.0;
    3654             :         }
    3655             : 
    3656             :         // set up the filter on method layer
    3657           8 :         CPLErrorReset();
    3658             :         OGRGeometry *x_geom =
    3659           8 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    3660           8 :         if (CPLGetLastErrorType() != CE_None)
    3661             :         {
    3662           0 :             if (!bSkipFailures)
    3663             :             {
    3664           0 :                 ret = OGRERR_FAILURE;
    3665           0 :                 goto done;
    3666             :             }
    3667             :             else
    3668             :             {
    3669           0 :                 CPLErrorReset();
    3670           0 :                 ret = OGRERR_NONE;
    3671             :             }
    3672             :         }
    3673           8 :         if (!x_geom)
    3674             :         {
    3675           0 :             continue;
    3676             :         }
    3677             : 
    3678             :         OGRGeometryUniquePtr geom(
    3679             :             x_geom
    3680           8 :                 ->clone());  // this will be the geometry of the result feature
    3681          15 :         for (auto &&y : pLayerMethod)
    3682             :         {
    3683           9 :             OGRGeometry *y_geom = y->GetGeometryRef();
    3684           9 :             if (!y_geom)
    3685             :             {
    3686           0 :                 continue;
    3687             :             }
    3688           9 :             if (geom)
    3689             :             {
    3690           9 :                 CPLErrorReset();
    3691           9 :                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    3692           9 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    3693             :                 {
    3694           0 :                     if (!bSkipFailures)
    3695             :                     {
    3696           0 :                         ret = OGRERR_FAILURE;
    3697           0 :                         goto done;
    3698             :                     }
    3699             :                     else
    3700             :                     {
    3701           0 :                         CPLErrorReset();
    3702           0 :                         ret = OGRERR_NONE;
    3703             :                     }
    3704             :                 }
    3705             :                 else
    3706             :                 {
    3707           9 :                     geom.swap(geom_new);
    3708             :                 }
    3709             :             }
    3710           9 :             if (geom && geom->IsEmpty())
    3711           2 :                 break;
    3712             :         }
    3713             : 
    3714           8 :         if (geom && !geom->IsEmpty())
    3715             :         {
    3716           6 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3717           6 :             z->SetFieldsFrom(x.get(), mapInput);
    3718           6 :             if (bPromoteToMulti)
    3719           2 :                 geom.reset(promote_to_multi(geom.release()));
    3720           6 :             z->SetGeometryDirectly(geom.release());
    3721           6 :             ret = pLayerResult->CreateFeature(z.get());
    3722           6 :             if (ret != OGRERR_NONE)
    3723             :             {
    3724           0 :                 if (!bSkipFailures)
    3725             :                 {
    3726           0 :                     goto done;
    3727             :                 }
    3728             :                 else
    3729             :                 {
    3730           0 :                     CPLErrorReset();
    3731           0 :                     ret = OGRERR_NONE;
    3732             :                 }
    3733             :             }
    3734             :         }
    3735             :     }
    3736             : 
    3737             :     // restore filter on method layer and add features based on it
    3738           4 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    3739          10 :     for (auto &&x : pLayerMethod)
    3740             :     {
    3741             : 
    3742           6 :         if (pfnProgress)
    3743             :         {
    3744           2 :             double p = progress_counter / progress_max;
    3745           2 :             if (p > progress_ticker)
    3746             :             {
    3747           2 :                 if (!pfnProgress(p, "", pProgressArg))
    3748             :                 {
    3749           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3750           0 :                     ret = OGRERR_FAILURE;
    3751           0 :                     goto done;
    3752             :                 }
    3753             :             }
    3754           2 :             progress_counter += 1.0;
    3755             :         }
    3756             : 
    3757             :         // set up the filter on input layer
    3758           6 :         CPLErrorReset();
    3759             :         OGRGeometry *x_geom =
    3760           6 :             set_filter_from(this, pGeometryInputFilter, x.get());
    3761           6 :         if (CPLGetLastErrorType() != CE_None)
    3762             :         {
    3763           0 :             if (!bSkipFailures)
    3764             :             {
    3765           0 :                 ret = OGRERR_FAILURE;
    3766           0 :                 goto done;
    3767             :             }
    3768             :             else
    3769             :             {
    3770           0 :                 CPLErrorReset();
    3771           0 :                 ret = OGRERR_NONE;
    3772             :             }
    3773             :         }
    3774           6 :         if (!x_geom)
    3775             :         {
    3776           0 :             continue;
    3777             :         }
    3778             : 
    3779             :         OGRGeometryUniquePtr geom(
    3780             :             x_geom
    3781           6 :                 ->clone());  // this will be the geometry of the result feature
    3782          13 :         for (auto &&y : this)
    3783             :         {
    3784           9 :             OGRGeometry *y_geom = y->GetGeometryRef();
    3785           9 :             if (!y_geom)
    3786           0 :                 continue;
    3787           9 :             if (geom)
    3788             :             {
    3789           9 :                 CPLErrorReset();
    3790           9 :                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    3791           9 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    3792             :                 {
    3793           0 :                     if (!bSkipFailures)
    3794             :                     {
    3795           0 :                         ret = OGRERR_FAILURE;
    3796           0 :                         goto done;
    3797             :                     }
    3798             :                     else
    3799             :                     {
    3800           0 :                         CPLErrorReset();
    3801           0 :                         ret = OGRERR_NONE;
    3802             :                     }
    3803             :                 }
    3804             :                 else
    3805             :                 {
    3806           9 :                     geom.swap(geom_new);
    3807             :                 }
    3808             :             }
    3809           9 :             if (geom == nullptr || geom->IsEmpty())
    3810           2 :                 break;
    3811             :         }
    3812             : 
    3813           6 :         if (geom && !geom->IsEmpty())
    3814             :         {
    3815           4 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    3816           4 :             z->SetFieldsFrom(x.get(), mapMethod);
    3817           4 :             if (bPromoteToMulti)
    3818           1 :                 geom.reset(promote_to_multi(geom.release()));
    3819           4 :             z->SetGeometryDirectly(geom.release());
    3820           4 :             ret = pLayerResult->CreateFeature(z.get());
    3821           4 :             if (ret != OGRERR_NONE)
    3822             :             {
    3823           0 :                 if (!bSkipFailures)
    3824             :                 {
    3825           0 :                     goto done;
    3826             :                 }
    3827             :                 else
    3828             :                 {
    3829           0 :                     CPLErrorReset();
    3830           0 :                     ret = OGRERR_NONE;
    3831             :                 }
    3832             :             }
    3833             :         }
    3834             :     }
    3835           4 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    3836             :     {
    3837           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3838           0 :         ret = OGRERR_FAILURE;
    3839           0 :         goto done;
    3840             :     }
    3841           4 : done:
    3842             :     // release resources
    3843           4 :     SetSpatialFilter(pGeometryInputFilter);
    3844           4 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    3845           4 :     if (pGeometryMethodFilter)
    3846           0 :         delete pGeometryMethodFilter;
    3847           4 :     if (pGeometryInputFilter)
    3848           0 :         delete pGeometryInputFilter;
    3849           4 :     if (mapInput)
    3850           3 :         VSIFree(mapInput);
    3851           4 :     if (mapMethod)
    3852           3 :         VSIFree(mapMethod);
    3853           4 :     return ret;
    3854             : }
    3855             : 
    3856             : /************************************************************************/
    3857             : /*                        OGR_L_SymDifference()                         */
    3858             : /************************************************************************/
    3859             : 
    3860             : /**
    3861             :  * \brief Symmetrical difference of two layers.
    3862             :  *
    3863             :  * The result layer contains features whose geometries represent areas
    3864             :  * that are in either in the input layer or in the method layer but
    3865             :  * not in both. The features in the result layer have attributes from
    3866             :  * both input and method layers. For features which represent areas
    3867             :  * that are only in the input or in the method layer the respective
    3868             :  * attributes have undefined values. The schema of the result layer
    3869             :  * can be set by the user or, if it is empty, is initialized to
    3870             :  * contain all fields in the input and method layers.
    3871             :  *
    3872             :  * \note If the schema of the result is set by user and contains
    3873             :  * fields that have the same name as a field in input and in method
    3874             :  * layer, then the attribute in the result feature will get the value
    3875             :  * from the feature of the method layer (even if it is undefined).
    3876             :  *
    3877             :  * \note For best performance use the minimum amount of features in
    3878             :  * the method layer and copy it into a memory layer.
    3879             :  *
    3880             :  * \note This method relies on GEOS support. Do not use unless the
    3881             :  * GEOS support is compiled in.
    3882             :  *
    3883             :  * The recognized list of options is :
    3884             :  * <ul>
    3885             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    3886             :  *     feature could not be inserted or a GEOS call failed.
    3887             :  * </li>
    3888             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    3889             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    3890             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    3891             :  * </li>
    3892             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3893             :  *     will be created from the fields of the input layer.
    3894             :  * </li>
    3895             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3896             :  *     will be created from the fields of the method layer.
    3897             :  * </li>
    3898             :  * </ul>
    3899             :  *
    3900             :  * This function is the same as the C++ method OGRLayer::SymDifference().
    3901             :  *
    3902             :  * @param pLayerInput the input layer. Should not be NULL.
    3903             :  *
    3904             :  * @param pLayerMethod the method layer. Should not be NULL.
    3905             :  *
    3906             :  * @param pLayerResult the layer where the features resulting from the
    3907             :  * operation are inserted. Should not be NULL. See above the note
    3908             :  * about the schema.
    3909             :  *
    3910             :  * @param papszOptions NULL terminated list of options (may be NULL).
    3911             :  *
    3912             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    3913             :  * reporting progress or NULL.
    3914             :  *
    3915             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    3916             :  *
    3917             :  * @return an error code if there was an error or the execution was
    3918             :  * interrupted, OGRERR_NONE otherwise.
    3919             :  *
    3920             :  * @note The first geometry field is always used.
    3921             :  *
    3922             :  * @since OGR 1.10
    3923             :  */
    3924             : 
    3925           4 : OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    3926             :                            OGRLayerH pLayerResult, char **papszOptions,
    3927             :                            GDALProgressFunc pfnProgress, void *pProgressArg)
    3928             : 
    3929             : {
    3930           4 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
    3931             :                       OGRERR_INVALID_HANDLE);
    3932           4 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
    3933             :                       OGRERR_INVALID_HANDLE);
    3934           4 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
    3935             :                       OGRERR_INVALID_HANDLE);
    3936             : 
    3937             :     return OGRLayer::FromHandle(pLayerInput)
    3938           4 :         ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
    3939             :                         OGRLayer::FromHandle(pLayerResult), papszOptions,
    3940           4 :                         pfnProgress, pProgressArg);
    3941             : }
    3942             : 
    3943             : /************************************************************************/
    3944             : /*                            Identity()                                */
    3945             : /************************************************************************/
    3946             : 
    3947             : /**
    3948             :  * \brief Identify the features of this layer with the ones from the
    3949             :  * identity layer.
    3950             :  *
    3951             :  * The result layer contains features whose geometries represent areas
    3952             :  * that are in the input layer. The features in the result layer have
    3953             :  * attributes from both input and method layers. The schema of the
    3954             :  * result layer can be set by the user or, if it is empty, is
    3955             :  * initialized to contain all fields in input and method layers.
    3956             :  *
    3957             :  * \note If the schema of the result is set by user and contains
    3958             :  * fields that have the same name as a field in input and in method
    3959             :  * layer, then the attribute in the result feature will get the value
    3960             :  * from the feature of the method layer (even if it is undefined).
    3961             :  *
    3962             :  * \note For best performance use the minimum amount of features in
    3963             :  * the method layer and copy it into a memory layer.
    3964             :  *
    3965             :  * \note This method relies on GEOS support. Do not use unless the
    3966             :  * GEOS support is compiled in.
    3967             :  *
    3968             :  * The recognized list of options is :
    3969             :  * <ul>
    3970             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    3971             :  *     feature could not be inserted or a GEOS call failed.
    3972             :  * </li>
    3973             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    3974             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    3975             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    3976             :  * </li>
    3977             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    3978             :  *     will be created from the fields of the input layer.
    3979             :  * </li>
    3980             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    3981             :  *     will be created from the fields of the method layer.
    3982             :  * </li>
    3983             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    3984             :  *     geometries to pretest intersection of features of method layer
    3985             :  *     with features of this layer.
    3986             :  * </li>
    3987             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    3988             :  *     result features with lower dimension geometry that would
    3989             :  *     otherwise be added to the result layer. The default is YES, to add
    3990             :  *     features with lower dimension geometry, but only if the result layer
    3991             :  *     has an unknown geometry type.
    3992             :  * </li>
    3993             :  * </ul>
    3994             :  *
    3995             :  * This method is the same as the C function OGR_L_Identity().
    3996             :  *
    3997             :  * @param pLayerMethod the method layer. Should not be NULL.
    3998             :  *
    3999             :  * @param pLayerResult the layer where the features resulting from the
    4000             :  * operation are inserted. Should not be NULL. See above the note
    4001             :  * about the schema.
    4002             :  *
    4003             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4004             :  *
    4005             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4006             :  * reporting progress or NULL.
    4007             :  *
    4008             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4009             :  *
    4010             :  * @return an error code if there was an error or the execution was
    4011             :  * interrupted, OGRERR_NONE otherwise.
    4012             :  *
    4013             :  * @note The first geometry field is always used.
    4014             :  *
    4015             :  * @since OGR 1.10
    4016             :  */
    4017             : 
    4018           6 : OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    4019             :                           char **papszOptions, GDALProgressFunc pfnProgress,
    4020             :                           void *pProgressArg)
    4021             : {
    4022           6 :     OGRErr ret = OGRERR_NONE;
    4023           6 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    4024           6 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    4025           6 :     OGRFeatureDefn *poDefnResult = nullptr;
    4026           6 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    4027           6 :     int *mapInput = nullptr;
    4028           6 :     int *mapMethod = nullptr;
    4029           6 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    4030           6 :     double progress_counter = 0;
    4031           6 :     double progress_ticker = 0;
    4032             :     const bool bSkipFailures =
    4033           6 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    4034           6 :     const bool bPromoteToMulti = CPLTestBool(
    4035             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    4036           6 :     const bool bUsePreparedGeometries = CPLTestBool(
    4037             :         CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
    4038           6 :     bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
    4039             :         papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
    4040             : 
    4041             :     // check for GEOS
    4042           6 :     if (!OGRGeometryFactory::haveGEOS())
    4043             :     {
    4044           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4045             :                  "OGRLayer::Identity() requires GEOS support");
    4046           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    4047             :     }
    4048           6 :     if (bKeepLowerDimGeom)
    4049             :     {
    4050             :         // require that the result layer is of geom type unknown
    4051           4 :         if (pLayerResult->GetGeomType() != wkbUnknown)
    4052             :         {
    4053           0 :             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
    4054             :                             "since the result layer does not allow it.");
    4055           0 :             bKeepLowerDimGeom = FALSE;
    4056             :         }
    4057             :     }
    4058             : 
    4059             :     // get resources
    4060           6 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    4061           6 :     if (ret != OGRERR_NONE)
    4062           0 :         goto done;
    4063           6 :     ret = create_field_map(poDefnInput, &mapInput);
    4064           6 :     if (ret != OGRERR_NONE)
    4065           0 :         goto done;
    4066           6 :     ret = create_field_map(poDefnMethod, &mapMethod);
    4067           6 :     if (ret != OGRERR_NONE)
    4068           0 :         goto done;
    4069           6 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    4070             :                             mapMethod, true, papszOptions);
    4071           6 :     if (ret != OGRERR_NONE)
    4072           0 :         goto done;
    4073           6 :     poDefnResult = pLayerResult->GetLayerDefn();
    4074             : 
    4075             :     // split the features in input layer to the result layer
    4076          18 :     for (auto &&x : this)
    4077             :     {
    4078             : 
    4079          12 :         if (pfnProgress)
    4080             :         {
    4081           2 :             double p = progress_counter / progress_max;
    4082           2 :             if (p > progress_ticker)
    4083             :             {
    4084           1 :                 if (!pfnProgress(p, "", pProgressArg))
    4085             :                 {
    4086           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4087           0 :                     ret = OGRERR_FAILURE;
    4088           0 :                     goto done;
    4089             :                 }
    4090             :             }
    4091           2 :             progress_counter += 1.0;
    4092             :         }
    4093             : 
    4094             :         // set up the filter on method layer
    4095          12 :         CPLErrorReset();
    4096             :         OGRGeometry *x_geom =
    4097          12 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    4098          12 :         if (CPLGetLastErrorType() != CE_None)
    4099             :         {
    4100           0 :             if (!bSkipFailures)
    4101             :             {
    4102           0 :                 ret = OGRERR_FAILURE;
    4103           0 :                 goto done;
    4104             :             }
    4105             :             else
    4106             :             {
    4107           0 :                 CPLErrorReset();
    4108           0 :                 ret = OGRERR_NONE;
    4109             :             }
    4110             :         }
    4111          12 :         if (!x_geom)
    4112             :         {
    4113           0 :             continue;
    4114             :         }
    4115             : 
    4116           0 :         OGRPreparedGeometryUniquePtr x_prepared_geom;
    4117          12 :         if (bUsePreparedGeometries)
    4118             :         {
    4119          12 :             x_prepared_geom.reset(
    4120             :                 OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
    4121          12 :             if (!x_prepared_geom)
    4122             :             {
    4123           0 :                 goto done;
    4124             :             }
    4125             :         }
    4126             : 
    4127             :         OGRGeometryUniquePtr x_geom_diff(
    4128             :             x_geom
    4129          12 :                 ->clone());  // this will be the geometry of the result feature
    4130          26 :         for (auto &&y : pLayerMethod)
    4131             :         {
    4132          14 :             OGRGeometry *y_geom = y->GetGeometryRef();
    4133          14 :             if (!y_geom)
    4134           0 :                 continue;
    4135             : 
    4136          14 :             CPLErrorReset();
    4137          28 :             if (x_prepared_geom &&
    4138          14 :                 !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
    4139          14 :                                                 OGRGeometry::ToHandle(y_geom))))
    4140             :             {
    4141           0 :                 if (CPLGetLastErrorType() == CE_None)
    4142             :                 {
    4143           0 :                     continue;
    4144             :                 }
    4145             :             }
    4146          14 :             if (CPLGetLastErrorType() != CE_None)
    4147             :             {
    4148           0 :                 if (!bSkipFailures)
    4149             :                 {
    4150           0 :                     ret = OGRERR_FAILURE;
    4151           0 :                     goto done;
    4152             :                 }
    4153             :                 else
    4154             :                 {
    4155           0 :                     CPLErrorReset();
    4156           0 :                     ret = OGRERR_NONE;
    4157             :                 }
    4158             :             }
    4159             : 
    4160          14 :             CPLErrorReset();
    4161          14 :             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
    4162          14 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    4163             :             {
    4164           0 :                 if (!bSkipFailures)
    4165             :                 {
    4166           0 :                     ret = OGRERR_FAILURE;
    4167           0 :                     goto done;
    4168             :                 }
    4169             :                 else
    4170             :                 {
    4171           0 :                     CPLErrorReset();
    4172           0 :                     ret = OGRERR_NONE;
    4173             :                 }
    4174             :             }
    4175          28 :             else if (poIntersection->IsEmpty() ||
    4176          14 :                      (!bKeepLowerDimGeom &&
    4177           6 :                       (x_geom->getDimension() == y_geom->getDimension() &&
    4178           6 :                        poIntersection->getDimension() <
    4179           6 :                            x_geom->getDimension())))
    4180             :             {
    4181             :                 /* ok*/
    4182             :             }
    4183             :             else
    4184             :             {
    4185          10 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4186          10 :                 z->SetFieldsFrom(x.get(), mapInput);
    4187          10 :                 z->SetFieldsFrom(y.get(), mapMethod);
    4188          10 :                 if (bPromoteToMulti)
    4189           2 :                     poIntersection.reset(
    4190             :                         promote_to_multi(poIntersection.release()));
    4191          10 :                 z->SetGeometryDirectly(poIntersection.release());
    4192          10 :                 if (x_geom_diff)
    4193             :                 {
    4194          10 :                     CPLErrorReset();
    4195             :                     OGRGeometryUniquePtr x_geom_diff_new(
    4196          10 :                         x_geom_diff->Difference(y_geom));
    4197          20 :                     if (CPLGetLastErrorType() != CE_None ||
    4198          10 :                         x_geom_diff_new == nullptr)
    4199             :                     {
    4200           0 :                         if (!bSkipFailures)
    4201             :                         {
    4202           0 :                             ret = OGRERR_FAILURE;
    4203           0 :                             goto done;
    4204             :                         }
    4205             :                         else
    4206             :                         {
    4207           0 :                             CPLErrorReset();
    4208             :                         }
    4209             :                     }
    4210             :                     else
    4211             :                     {
    4212          10 :                         x_geom_diff.swap(x_geom_diff_new);
    4213             :                     }
    4214             :                 }
    4215          10 :                 ret = pLayerResult->CreateFeature(z.get());
    4216          10 :                 if (ret != OGRERR_NONE)
    4217             :                 {
    4218           0 :                     if (!bSkipFailures)
    4219             :                     {
    4220           0 :                         goto done;
    4221             :                     }
    4222             :                     else
    4223             :                     {
    4224           0 :                         CPLErrorReset();
    4225           0 :                         ret = OGRERR_NONE;
    4226             :                     }
    4227             :                 }
    4228             :             }
    4229             :         }
    4230             : 
    4231          12 :         x_prepared_geom.reset();
    4232             : 
    4233          12 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    4234             :         {
    4235             :             /* ok */
    4236             :         }
    4237             :         else
    4238             :         {
    4239          10 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4240          10 :             z->SetFieldsFrom(x.get(), mapInput);
    4241          10 :             if (bPromoteToMulti)
    4242           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    4243          10 :             z->SetGeometryDirectly(x_geom_diff.release());
    4244          10 :             ret = pLayerResult->CreateFeature(z.get());
    4245          10 :             if (ret != OGRERR_NONE)
    4246             :             {
    4247           0 :                 if (!bSkipFailures)
    4248             :                 {
    4249           0 :                     goto done;
    4250             :                 }
    4251             :                 else
    4252             :                 {
    4253           0 :                     CPLErrorReset();
    4254           0 :                     ret = OGRERR_NONE;
    4255             :                 }
    4256             :             }
    4257             :         }
    4258             :     }
    4259           6 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    4260             :     {
    4261           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4262           0 :         ret = OGRERR_FAILURE;
    4263           0 :         goto done;
    4264             :     }
    4265           6 : done:
    4266             :     // release resources
    4267           6 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4268           6 :     if (pGeometryMethodFilter)
    4269           0 :         delete pGeometryMethodFilter;
    4270           6 :     if (mapInput)
    4271           3 :         VSIFree(mapInput);
    4272           6 :     if (mapMethod)
    4273           3 :         VSIFree(mapMethod);
    4274           6 :     return ret;
    4275             : }
    4276             : 
    4277             : /************************************************************************/
    4278             : /*                         OGR_L_Identity()                             */
    4279             : /************************************************************************/
    4280             : 
    4281             : /**
    4282             :  * \brief Identify the features of this layer with the ones from the
    4283             :  * identity layer.
    4284             :  *
    4285             :  * The result layer contains features whose geometries represent areas
    4286             :  * that are in the input layer. The features in the result layer have
    4287             :  * attributes from both input and method layers. The schema of the
    4288             :  * result layer can be set by the user or, if it is empty, is
    4289             :  * initialized to contain all fields in input and method layers.
    4290             :  *
    4291             :  * \note If the schema of the result is set by user and contains
    4292             :  * fields that have the same name as a field in input and in method
    4293             :  * layer, then the attribute in the result feature will get the value
    4294             :  * from the feature of the method layer (even if it is undefined).
    4295             :  *
    4296             :  * \note For best performance use the minimum amount of features in
    4297             :  * the method layer and copy it into a memory layer.
    4298             :  *
    4299             :  * \note This method relies on GEOS support. Do not use unless the
    4300             :  * GEOS support is compiled in.
    4301             :  *
    4302             :  * The recognized list of options is :
    4303             :  * <ul>
    4304             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4305             :  *     feature could not be inserted or a GEOS call failed.
    4306             :  * </li>
    4307             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4308             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4309             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4310             :  * </li>
    4311             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4312             :  *     will be created from the fields of the input layer.
    4313             :  * </li>
    4314             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4315             :  *     will be created from the fields of the method layer.
    4316             :  * </li>
    4317             :  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
    4318             :  *     geometries to pretest intersection of features of method layer
    4319             :  *     with features of this layer.
    4320             :  * </li>
    4321             :  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
    4322             :  *     result features with lower dimension geometry that would
    4323             :  *     otherwise be added to the result layer. The default is YES, to add
    4324             :  *     features with lower dimension geometry, but only if the result layer
    4325             :  *     has an unknown geometry type.
    4326             :  * </li>
    4327             :  * </ul>
    4328             :  *
    4329             :  * This function is the same as the C++ method OGRLayer::Identity().
    4330             :  *
    4331             :  * @param pLayerInput the input layer. Should not be NULL.
    4332             :  *
    4333             :  * @param pLayerMethod the method layer. Should not be NULL.
    4334             :  *
    4335             :  * @param pLayerResult the layer where the features resulting from the
    4336             :  * operation are inserted. Should not be NULL. See above the note
    4337             :  * about the schema.
    4338             :  *
    4339             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4340             :  *
    4341             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4342             :  * reporting progress or NULL.
    4343             :  *
    4344             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4345             :  *
    4346             :  * @return an error code if there was an error or the execution was
    4347             :  * interrupted, OGRERR_NONE otherwise.
    4348             :  *
    4349             :  * @note The first geometry field is always used.
    4350             :  *
    4351             :  * @since OGR 1.10
    4352             :  */
    4353             : 
    4354           6 : OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    4355             :                       OGRLayerH pLayerResult, char **papszOptions,
    4356             :                       GDALProgressFunc pfnProgress, void *pProgressArg)
    4357             : 
    4358             : {
    4359           6 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    4360           6 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    4361           6 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
    4362             : 
    4363             :     return OGRLayer::FromHandle(pLayerInput)
    4364           6 :         ->Identity(OGRLayer::FromHandle(pLayerMethod),
    4365             :                    OGRLayer::FromHandle(pLayerResult), papszOptions,
    4366           6 :                    pfnProgress, pProgressArg);
    4367             : }
    4368             : 
    4369             : /************************************************************************/
    4370             : /*                             Update()                                 */
    4371             : /************************************************************************/
    4372             : 
    4373             : /**
    4374             :  * \brief Update this layer with features from the update layer.
    4375             :  *
    4376             :  * The result layer contains features whose geometries represent areas
    4377             :  * that are either in the input layer or in the method layer. The
    4378             :  * features in the result layer have areas of the features of the
    4379             :  * method layer or those ares of the features of the input layer that
    4380             :  * are not covered by the method layer. The features of the result
    4381             :  * layer get their attributes from the input layer. The schema of the
    4382             :  * result layer can be set by the user or, if it is empty, is
    4383             :  * initialized to contain all fields in the input layer.
    4384             :  *
    4385             :  * \note If the schema of the result is set by user and contains
    4386             :  * fields that have the same name as a field in the method layer, then
    4387             :  * the attribute in the result feature the originates from the method
    4388             :  * layer will get the value from the feature of the method layer.
    4389             :  *
    4390             :  * \note For best performance use the minimum amount of features in
    4391             :  * the method layer and copy it into a memory layer.
    4392             :  *
    4393             :  * \note This method relies on GEOS support. Do not use unless the
    4394             :  * GEOS support is compiled in.
    4395             :  *
    4396             :  * The recognized list of options is :
    4397             :  * <ul>
    4398             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4399             :  *     feature could not be inserted or a GEOS call failed.
    4400             :  * </li>
    4401             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4402             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4403             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4404             :  * </li>
    4405             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4406             :  *     will be created from the fields of the input layer.
    4407             :  * </li>
    4408             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4409             :  *     will be created from the fields of the method layer.
    4410             :  * </li>
    4411             :  * </ul>
    4412             :  *
    4413             :  * This method is the same as the C function OGR_L_Update().
    4414             :  *
    4415             :  * @param pLayerMethod the method layer. Should not be NULL.
    4416             :  *
    4417             :  * @param pLayerResult the layer where the features resulting from the
    4418             :  * operation are inserted. Should not be NULL. See above the note
    4419             :  * about the schema.
    4420             :  *
    4421             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4422             :  *
    4423             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4424             :  * reporting progress or NULL.
    4425             :  *
    4426             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4427             :  *
    4428             :  * @return an error code if there was an error or the execution was
    4429             :  * interrupted, OGRERR_NONE otherwise.
    4430             :  *
    4431             :  * @note The first geometry field is always used.
    4432             :  *
    4433             :  * @since OGR 1.10
    4434             :  */
    4435             : 
    4436           5 : OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    4437             :                         char **papszOptions, GDALProgressFunc pfnProgress,
    4438             :                         void *pProgressArg)
    4439             : {
    4440           5 :     OGRErr ret = OGRERR_NONE;
    4441           5 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    4442           5 :     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
    4443           5 :     OGRFeatureDefn *poDefnResult = nullptr;
    4444           5 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    4445           5 :     int *mapInput = nullptr;
    4446           5 :     int *mapMethod = nullptr;
    4447             :     double progress_max =
    4448           5 :         static_cast<double>(GetFeatureCount(FALSE)) +
    4449           5 :         static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
    4450           5 :     double progress_counter = 0;
    4451           5 :     double progress_ticker = 0;
    4452             :     const bool bSkipFailures =
    4453           5 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    4454           5 :     const bool bPromoteToMulti = CPLTestBool(
    4455             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    4456             : 
    4457             :     // check for GEOS
    4458           5 :     if (!OGRGeometryFactory::haveGEOS())
    4459             :     {
    4460           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4461             :                  "OGRLayer::Update() requires GEOS support");
    4462           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    4463             :     }
    4464             : 
    4465             :     // get resources
    4466           5 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    4467           5 :     if (ret != OGRERR_NONE)
    4468           0 :         goto done;
    4469           5 :     ret = create_field_map(poDefnInput, &mapInput);
    4470           5 :     if (ret != OGRERR_NONE)
    4471           0 :         goto done;
    4472           5 :     ret = create_field_map(poDefnMethod, &mapMethod);
    4473           5 :     if (ret != OGRERR_NONE)
    4474           0 :         goto done;
    4475           5 :     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
    4476             :                             mapMethod, false, papszOptions);
    4477           5 :     if (ret != OGRERR_NONE)
    4478           0 :         goto done;
    4479           5 :     poDefnResult = pLayerResult->GetLayerDefn();
    4480             : 
    4481             :     // add clipped features from the input layer
    4482          15 :     for (auto &&x : this)
    4483             :     {
    4484             : 
    4485          10 :         if (pfnProgress)
    4486             :         {
    4487           2 :             double p = progress_counter / progress_max;
    4488           2 :             if (p > progress_ticker)
    4489             :             {
    4490           1 :                 if (!pfnProgress(p, "", pProgressArg))
    4491             :                 {
    4492           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4493           0 :                     ret = OGRERR_FAILURE;
    4494           0 :                     goto done;
    4495             :                 }
    4496             :             }
    4497           2 :             progress_counter += 1.0;
    4498             :         }
    4499             : 
    4500             :         // set up the filter on method layer
    4501          10 :         CPLErrorReset();
    4502             :         OGRGeometry *x_geom =
    4503          10 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    4504          10 :         if (CPLGetLastErrorType() != CE_None)
    4505             :         {
    4506           0 :             if (!bSkipFailures)
    4507             :             {
    4508           0 :                 ret = OGRERR_FAILURE;
    4509           0 :                 goto done;
    4510             :             }
    4511             :             else
    4512             :             {
    4513           0 :                 CPLErrorReset();
    4514           0 :                 ret = OGRERR_NONE;
    4515             :             }
    4516             :         }
    4517          10 :         if (!x_geom)
    4518             :         {
    4519           0 :             continue;
    4520             :         }
    4521             : 
    4522             :         OGRGeometryUniquePtr x_geom_diff(
    4523          10 :             x_geom->clone());  // this will be the geometry of a result feature
    4524          24 :         for (auto &&y : pLayerMethod)
    4525             :         {
    4526          14 :             OGRGeometry *y_geom = y->GetGeometryRef();
    4527          14 :             if (!y_geom)
    4528           0 :                 continue;
    4529          14 :             if (x_geom_diff)
    4530             :             {
    4531          14 :                 CPLErrorReset();
    4532             :                 OGRGeometryUniquePtr x_geom_diff_new(
    4533          14 :                     x_geom_diff->Difference(y_geom));
    4534          28 :                 if (CPLGetLastErrorType() != CE_None ||
    4535          14 :                     x_geom_diff_new == nullptr)
    4536             :                 {
    4537           0 :                     if (!bSkipFailures)
    4538             :                     {
    4539           0 :                         ret = OGRERR_FAILURE;
    4540           0 :                         goto done;
    4541             :                     }
    4542             :                     else
    4543             :                     {
    4544           0 :                         CPLErrorReset();
    4545           0 :                         ret = OGRERR_NONE;
    4546             :                     }
    4547             :                 }
    4548             :                 else
    4549             :                 {
    4550          14 :                     x_geom_diff.swap(x_geom_diff_new);
    4551             :                 }
    4552             :             }
    4553             :         }
    4554             : 
    4555          10 :         if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
    4556             :         {
    4557             :             /* ok */
    4558             :         }
    4559             :         else
    4560             :         {
    4561           6 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4562           6 :             z->SetFieldsFrom(x.get(), mapInput);
    4563           6 :             if (bPromoteToMulti)
    4564           2 :                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
    4565           6 :             z->SetGeometryDirectly(x_geom_diff.release());
    4566           6 :             ret = pLayerResult->CreateFeature(z.get());
    4567           6 :             if (ret != OGRERR_NONE)
    4568             :             {
    4569           0 :                 if (!bSkipFailures)
    4570             :                 {
    4571           0 :                     goto done;
    4572             :                 }
    4573             :                 else
    4574             :                 {
    4575           0 :                     CPLErrorReset();
    4576           0 :                     ret = OGRERR_NONE;
    4577             :                 }
    4578             :             }
    4579             :         }
    4580             :     }
    4581             : 
    4582             :     // restore the original filter and add features from the update layer
    4583           5 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4584          12 :     for (auto &&y : pLayerMethod)
    4585             :     {
    4586             : 
    4587           7 :         if (pfnProgress)
    4588             :         {
    4589           1 :             double p = progress_counter / progress_max;
    4590           1 :             if (p > progress_ticker)
    4591             :             {
    4592           1 :                 if (!pfnProgress(p, "", pProgressArg))
    4593             :                 {
    4594           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4595           0 :                     ret = OGRERR_FAILURE;
    4596           0 :                     goto done;
    4597             :                 }
    4598             :             }
    4599           1 :             progress_counter += 1.0;
    4600             :         }
    4601             : 
    4602           7 :         OGRGeometry *y_geom = y->StealGeometry();
    4603           7 :         if (!y_geom)
    4604           0 :             continue;
    4605           7 :         OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4606           7 :         if (mapMethod)
    4607           3 :             z->SetFieldsFrom(y.get(), mapMethod);
    4608           7 :         z->SetGeometryDirectly(y_geom);
    4609           7 :         ret = pLayerResult->CreateFeature(z.get());
    4610           7 :         if (ret != OGRERR_NONE)
    4611             :         {
    4612           0 :             if (!bSkipFailures)
    4613             :             {
    4614           0 :                 goto done;
    4615             :             }
    4616             :             else
    4617             :             {
    4618           0 :                 CPLErrorReset();
    4619           0 :                 ret = OGRERR_NONE;
    4620             :             }
    4621             :         }
    4622             :     }
    4623           5 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    4624             :     {
    4625           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4626           0 :         ret = OGRERR_FAILURE;
    4627           0 :         goto done;
    4628             :     }
    4629           5 : done:
    4630             :     // release resources
    4631           5 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4632           5 :     if (pGeometryMethodFilter)
    4633           0 :         delete pGeometryMethodFilter;
    4634           5 :     if (mapInput)
    4635           3 :         VSIFree(mapInput);
    4636           5 :     if (mapMethod)
    4637           3 :         VSIFree(mapMethod);
    4638           5 :     return ret;
    4639             : }
    4640             : 
    4641             : /************************************************************************/
    4642             : /*                          OGR_L_Update()                              */
    4643             : /************************************************************************/
    4644             : 
    4645             : /**
    4646             :  * \brief Update this layer with features from the update layer.
    4647             :  *
    4648             :  * The result layer contains features whose geometries represent areas
    4649             :  * that are either in the input layer or in the method layer. The
    4650             :  * features in the result layer have areas of the features of the
    4651             :  * method layer or those ares of the features of the input layer that
    4652             :  * are not covered by the method layer. The features of the result
    4653             :  * layer get their attributes from the input layer. The schema of the
    4654             :  * result layer can be set by the user or, if it is empty, is
    4655             :  * initialized to contain all fields in the input layer.
    4656             :  *
    4657             :  * \note If the schema of the result is set by user and contains
    4658             :  * fields that have the same name as a field in the method layer, then
    4659             :  * the attribute in the result feature the originates from the method
    4660             :  * layer will get the value from the feature of the method layer.
    4661             :  *
    4662             :  * \note For best performance use the minimum amount of features in
    4663             :  * the method layer and copy it into a memory layer.
    4664             :  *
    4665             :  * \note This method relies on GEOS support. Do not use unless the
    4666             :  * GEOS support is compiled in.
    4667             :  *
    4668             :  * The recognized list of options is :
    4669             :  * <ul>
    4670             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4671             :  *     feature could not be inserted or a GEOS call failed.
    4672             :  * </li>
    4673             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4674             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4675             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4676             :  * </li>
    4677             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4678             :  *     will be created from the fields of the input layer.
    4679             :  * </li>
    4680             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4681             :  *     will be created from the fields of the method layer.
    4682             :  * </li>
    4683             :  * </ul>
    4684             :  *
    4685             :  * This function is the same as the C++ method OGRLayer::Update().
    4686             :  *
    4687             :  * @param pLayerInput the input layer. Should not be NULL.
    4688             :  *
    4689             :  * @param pLayerMethod the method layer. Should not be NULL.
    4690             :  *
    4691             :  * @param pLayerResult the layer where the features resulting from the
    4692             :  * operation are inserted. Should not be NULL. See above the note
    4693             :  * about the schema.
    4694             :  *
    4695             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4696             :  *
    4697             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4698             :  * reporting progress or NULL.
    4699             :  *
    4700             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4701             :  *
    4702             :  * @return an error code if there was an error or the execution was
    4703             :  * interrupted, OGRERR_NONE otherwise.
    4704             :  *
    4705             :  * @note The first geometry field is always used.
    4706             :  *
    4707             :  * @since OGR 1.10
    4708             :  */
    4709             : 
    4710           5 : OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    4711             :                     OGRLayerH pLayerResult, char **papszOptions,
    4712             :                     GDALProgressFunc pfnProgress, void *pProgressArg)
    4713             : 
    4714             : {
    4715           5 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    4716           5 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    4717           5 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
    4718             : 
    4719             :     return OGRLayer::FromHandle(pLayerInput)
    4720           5 :         ->Update(OGRLayer::FromHandle(pLayerMethod),
    4721             :                  OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    4722           5 :                  pProgressArg);
    4723             : }
    4724             : 
    4725             : /************************************************************************/
    4726             : /*                              Clip()                                  */
    4727             : /************************************************************************/
    4728             : 
    4729             : /**
    4730             :  * \brief Clip off areas that are not covered by the method layer.
    4731             :  *
    4732             :  * The result layer contains features whose geometries represent areas
    4733             :  * that are in the input layer and in the method layer. The features
    4734             :  * in the result layer have the (possibly clipped) areas of features
    4735             :  * in the input layer and the attributes from the same features. The
    4736             :  * schema of the result layer can be set by the user or, if it is
    4737             :  * empty, is initialized to contain all fields in the input layer.
    4738             :  *
    4739             :  * \note For best performance use the minimum amount of features in
    4740             :  * the method layer and copy it into a memory layer.
    4741             :  *
    4742             :  * \note This method relies on GEOS support. Do not use unless the
    4743             :  * GEOS support is compiled in.
    4744             :  *
    4745             :  * The recognized list of options is :
    4746             :  * <ul>
    4747             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4748             :  *     feature could not be inserted or a GEOS call failed.
    4749             :  * </li>
    4750             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4751             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4752             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4753             :  * </li>
    4754             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4755             :  *     will be created from the fields of the input layer.
    4756             :  * </li>
    4757             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4758             :  *     will be created from the fields of the method layer.
    4759             :  * </li>
    4760             :  * </ul>
    4761             :  *
    4762             :  * This method is the same as the C function OGR_L_Clip().
    4763             :  *
    4764             :  * @param pLayerMethod the method layer. Should not be NULL.
    4765             :  *
    4766             :  * @param pLayerResult the layer where the features resulting from the
    4767             :  * operation are inserted. Should not be NULL. See above the note
    4768             :  * about the schema.
    4769             :  *
    4770             :  * @param papszOptions NULL terminated list of options (may be NULL).
    4771             :  *
    4772             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    4773             :  * reporting progress or NULL.
    4774             :  *
    4775             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    4776             :  *
    4777             :  * @return an error code if there was an error or the execution was
    4778             :  * interrupted, OGRERR_NONE otherwise.
    4779             :  *
    4780             :  * @note The first geometry field is always used.
    4781             :  *
    4782             :  * @since OGR 1.10
    4783             :  */
    4784             : 
    4785           3 : OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    4786             :                       char **papszOptions, GDALProgressFunc pfnProgress,
    4787             :                       void *pProgressArg)
    4788             : {
    4789           3 :     OGRErr ret = OGRERR_NONE;
    4790           3 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    4791           3 :     OGRFeatureDefn *poDefnResult = nullptr;
    4792           3 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    4793           3 :     int *mapInput = nullptr;
    4794           3 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    4795           3 :     double progress_counter = 0;
    4796           3 :     double progress_ticker = 0;
    4797             :     const bool bSkipFailures =
    4798           3 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    4799           3 :     const bool bPromoteToMulti = CPLTestBool(
    4800             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    4801             : 
    4802             :     // check for GEOS
    4803           3 :     if (!OGRGeometryFactory::haveGEOS())
    4804             :     {
    4805           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4806             :                  "OGRLayer::Clip() requires GEOS support");
    4807           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    4808             :     }
    4809             : 
    4810           3 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    4811           3 :     if (ret != OGRERR_NONE)
    4812           0 :         goto done;
    4813           3 :     ret = create_field_map(poDefnInput, &mapInput);
    4814           3 :     if (ret != OGRERR_NONE)
    4815           0 :         goto done;
    4816           3 :     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
    4817             :                             nullptr, false, papszOptions);
    4818           3 :     if (ret != OGRERR_NONE)
    4819           0 :         goto done;
    4820             : 
    4821           3 :     poDefnResult = pLayerResult->GetLayerDefn();
    4822           9 :     for (auto &&x : this)
    4823             :     {
    4824             : 
    4825           6 :         if (pfnProgress)
    4826             :         {
    4827           2 :             double p = progress_counter / progress_max;
    4828           2 :             if (p > progress_ticker)
    4829             :             {
    4830           1 :                 if (!pfnProgress(p, "", pProgressArg))
    4831             :                 {
    4832           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4833           0 :                     ret = OGRERR_FAILURE;
    4834           0 :                     goto done;
    4835             :                 }
    4836             :             }
    4837           2 :             progress_counter += 1.0;
    4838             :         }
    4839             : 
    4840             :         // set up the filter on method layer
    4841           6 :         CPLErrorReset();
    4842             :         OGRGeometry *x_geom =
    4843           6 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    4844           6 :         if (CPLGetLastErrorType() != CE_None)
    4845             :         {
    4846           0 :             if (!bSkipFailures)
    4847             :             {
    4848           0 :                 ret = OGRERR_FAILURE;
    4849           0 :                 goto done;
    4850             :             }
    4851             :             else
    4852             :             {
    4853           0 :                 CPLErrorReset();
    4854           0 :                 ret = OGRERR_NONE;
    4855             :             }
    4856             :         }
    4857           6 :         if (!x_geom)
    4858             :         {
    4859           0 :             continue;
    4860             :         }
    4861             : 
    4862             :         OGRGeometryUniquePtr
    4863           0 :             geom;  // this will be the geometry of the result feature
    4864             :         // incrementally add area from y to geom
    4865          12 :         for (auto &&y : pLayerMethod)
    4866             :         {
    4867           6 :             OGRGeometry *y_geom = y->GetGeometryRef();
    4868           6 :             if (!y_geom)
    4869           0 :                 continue;
    4870           6 :             if (!geom)
    4871             :             {
    4872           6 :                 geom.reset(y_geom->clone());
    4873             :             }
    4874             :             else
    4875             :             {
    4876           0 :                 CPLErrorReset();
    4877           0 :                 OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
    4878           0 :                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    4879             :                 {
    4880           0 :                     if (!bSkipFailures)
    4881             :                     {
    4882           0 :                         ret = OGRERR_FAILURE;
    4883           0 :                         goto done;
    4884             :                     }
    4885             :                     else
    4886             :                     {
    4887           0 :                         CPLErrorReset();
    4888           0 :                         ret = OGRERR_NONE;
    4889             :                     }
    4890             :                 }
    4891             :                 else
    4892             :                 {
    4893           0 :                     geom.swap(geom_new);
    4894             :                 }
    4895             :             }
    4896             :         }
    4897             : 
    4898             :         // possibly add a new feature with area x intersection sum of y
    4899           6 :         if (geom)
    4900             :         {
    4901           6 :             CPLErrorReset();
    4902             :             OGRGeometryUniquePtr poIntersection(
    4903           6 :                 x_geom->Intersection(geom.get()));
    4904           6 :             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
    4905             :             {
    4906           0 :                 if (!bSkipFailures)
    4907             :                 {
    4908           0 :                     ret = OGRERR_FAILURE;
    4909           0 :                     goto done;
    4910             :                 }
    4911             :                 else
    4912             :                 {
    4913           0 :                     CPLErrorReset();
    4914           0 :                     ret = OGRERR_NONE;
    4915             :                 }
    4916             :             }
    4917           6 :             else if (!poIntersection->IsEmpty())
    4918             :             {
    4919           6 :                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    4920           6 :                 z->SetFieldsFrom(x.get(), mapInput);
    4921           6 :                 if (bPromoteToMulti)
    4922           2 :                     poIntersection.reset(
    4923             :                         promote_to_multi(poIntersection.release()));
    4924           6 :                 z->SetGeometryDirectly(poIntersection.release());
    4925           6 :                 ret = pLayerResult->CreateFeature(z.get());
    4926           6 :                 if (ret != OGRERR_NONE)
    4927             :                 {
    4928           0 :                     if (!bSkipFailures)
    4929             :                     {
    4930           0 :                         goto done;
    4931             :                     }
    4932             :                     else
    4933             :                     {
    4934           0 :                         CPLErrorReset();
    4935           0 :                         ret = OGRERR_NONE;
    4936             :                     }
    4937             :                 }
    4938             :             }
    4939             :         }
    4940             :     }
    4941           3 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    4942             :     {
    4943           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4944           0 :         ret = OGRERR_FAILURE;
    4945           0 :         goto done;
    4946             :     }
    4947           3 : done:
    4948             :     // release resources
    4949           3 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    4950           3 :     if (pGeometryMethodFilter)
    4951           0 :         delete pGeometryMethodFilter;
    4952           3 :     if (mapInput)
    4953           3 :         VSIFree(mapInput);
    4954           3 :     return ret;
    4955             : }
    4956             : 
    4957             : /************************************************************************/
    4958             : /*                           OGR_L_Clip()                               */
    4959             : /************************************************************************/
    4960             : 
    4961             : /**
    4962             :  * \brief Clip off areas that are not covered by the method layer.
    4963             :  *
    4964             :  * The result layer contains features whose geometries represent areas
    4965             :  * that are in the input layer and in the method layer. The features
    4966             :  * in the result layer have the (possibly clipped) areas of features
    4967             :  * in the input layer and the attributes from the same features. The
    4968             :  * schema of the result layer can be set by the user or, if it is
    4969             :  * empty, is initialized to contain all fields in the input layer.
    4970             :  *
    4971             :  * \note For best performance use the minimum amount of features in
    4972             :  * the method layer and copy it into a memory layer.
    4973             :  *
    4974             :  * \note This method relies on GEOS support. Do not use unless the
    4975             :  * GEOS support is compiled in.
    4976             :  *
    4977             :  * The recognized list of options is :
    4978             :  * <ul>
    4979             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    4980             :  *     feature could not be inserted or a GEOS call failed.
    4981             :  * </li>
    4982             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    4983             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    4984             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    4985             :  * </li>
    4986             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    4987             :  *     will be created from the fields of the input layer.
    4988             :  * </li>
    4989             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    4990             :  *     will be created from the fields of the method layer.
    4991             :  * </li>
    4992             :  * </ul>
    4993             :  *
    4994             :  * This function is the same as the C++ method OGRLayer::Clip().
    4995             :  *
    4996             :  * @param pLayerInput the input layer. Should not be NULL.
    4997             :  *
    4998             :  * @param pLayerMethod the method layer. Should not be NULL.
    4999             :  *
    5000             :  * @param pLayerResult the layer where the features resulting from the
    5001             :  * operation are inserted. Should not be NULL. See above the note
    5002             :  * about the schema.
    5003             :  *
    5004             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5005             :  *
    5006             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5007             :  * reporting progress or NULL.
    5008             :  *
    5009             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5010             :  *
    5011             :  * @return an error code if there was an error or the execution was
    5012             :  * interrupted, OGRERR_NONE otherwise.
    5013             :  *
    5014             :  * @note The first geometry field is always used.
    5015             :  *
    5016             :  * @since OGR 1.10
    5017             :  */
    5018             : 
    5019           3 : OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    5020             :                   OGRLayerH pLayerResult, char **papszOptions,
    5021             :                   GDALProgressFunc pfnProgress, void *pProgressArg)
    5022             : 
    5023             : {
    5024           3 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    5025           3 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    5026           3 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
    5027             : 
    5028             :     return OGRLayer::FromHandle(pLayerInput)
    5029           3 :         ->Clip(OGRLayer::FromHandle(pLayerMethod),
    5030             :                OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    5031           3 :                pProgressArg);
    5032             : }
    5033             : 
    5034             : /************************************************************************/
    5035             : /*                              Erase()                                 */
    5036             : /************************************************************************/
    5037             : 
    5038             : /**
    5039             :  * \brief Remove areas that are covered by the method layer.
    5040             :  *
    5041             :  * The result layer contains features whose geometries represent areas
    5042             :  * that are in the input layer but not in the method layer. The
    5043             :  * features in the result layer have attributes from the input
    5044             :  * layer. The schema of the result layer can be set by the user or, if
    5045             :  * it is empty, is initialized to contain all fields in the input
    5046             :  * layer.
    5047             :  *
    5048             :  * \note For best performance use the minimum amount of features in
    5049             :  * the method layer and copy it into a memory layer.
    5050             :  *
    5051             :  * \note This method relies on GEOS support. Do not use unless the
    5052             :  * GEOS support is compiled in.
    5053             :  *
    5054             :  * The recognized list of options is :
    5055             :  * <ul>
    5056             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5057             :  *     feature could not be inserted or a GEOS call failed.
    5058             :  * </li>
    5059             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5060             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5061             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5062             :  * </li>
    5063             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5064             :  *     will be created from the fields of the input layer.
    5065             :  * </li>
    5066             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5067             :  *     will be created from the fields of the method layer.
    5068             :  * </li>
    5069             :  * </ul>
    5070             :  *
    5071             :  * This method is the same as the C function OGR_L_Erase().
    5072             :  *
    5073             :  * @param pLayerMethod the method layer. Should not be NULL.
    5074             :  *
    5075             :  * @param pLayerResult the layer where the features resulting from the
    5076             :  * operation are inserted. Should not be NULL. See above the note
    5077             :  * about the schema.
    5078             :  *
    5079             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5080             :  *
    5081             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5082             :  * reporting progress or NULL.
    5083             :  *
    5084             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5085             :  *
    5086             :  * @return an error code if there was an error or the execution was
    5087             :  * interrupted, OGRERR_NONE otherwise.
    5088             :  *
    5089             :  * @note The first geometry field is always used.
    5090             :  *
    5091             :  * @since OGR 1.10
    5092             :  */
    5093             : 
    5094           6 : OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
    5095             :                        char **papszOptions, GDALProgressFunc pfnProgress,
    5096             :                        void *pProgressArg)
    5097             : {
    5098           6 :     OGRErr ret = OGRERR_NONE;
    5099           6 :     OGRFeatureDefn *poDefnInput = GetLayerDefn();
    5100           6 :     OGRFeatureDefn *poDefnResult = nullptr;
    5101           6 :     OGRGeometry *pGeometryMethodFilter = nullptr;
    5102           6 :     int *mapInput = nullptr;
    5103           6 :     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
    5104           6 :     double progress_counter = 0;
    5105           6 :     double progress_ticker = 0;
    5106             :     const bool bSkipFailures =
    5107           6 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
    5108           6 :     const bool bPromoteToMulti = CPLTestBool(
    5109             :         CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
    5110             : 
    5111             :     // check for GEOS
    5112           6 :     if (!OGRGeometryFactory::haveGEOS())
    5113             :     {
    5114           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    5115             :                  "OGRLayer::Erase() requires GEOS support");
    5116           0 :         return OGRERR_UNSUPPORTED_OPERATION;
    5117             :     }
    5118             : 
    5119             :     // get resources
    5120           6 :     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
    5121           6 :     if (ret != OGRERR_NONE)
    5122           0 :         goto done;
    5123           6 :     ret = create_field_map(poDefnInput, &mapInput);
    5124           6 :     if (ret != OGRERR_NONE)
    5125           0 :         goto done;
    5126           6 :     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
    5127             :                             nullptr, false, papszOptions);
    5128           6 :     if (ret != OGRERR_NONE)
    5129           0 :         goto done;
    5130           6 :     poDefnResult = pLayerResult->GetLayerDefn();
    5131             : 
    5132          18 :     for (auto &&x : this)
    5133             :     {
    5134             : 
    5135          12 :         if (pfnProgress)
    5136             :         {
    5137           2 :             double p = progress_counter / progress_max;
    5138           2 :             if (p > progress_ticker)
    5139             :             {
    5140           1 :                 if (!pfnProgress(p, "", pProgressArg))
    5141             :                 {
    5142           0 :                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5143           0 :                     ret = OGRERR_FAILURE;
    5144           0 :                     goto done;
    5145             :                 }
    5146             :             }
    5147           2 :             progress_counter += 1.0;
    5148             :         }
    5149             : 
    5150             :         // set up the filter on the method layer
    5151          12 :         CPLErrorReset();
    5152             :         OGRGeometry *x_geom =
    5153          12 :             set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
    5154          12 :         if (CPLGetLastErrorType() != CE_None)
    5155             :         {
    5156           0 :             if (!bSkipFailures)
    5157             :             {
    5158           0 :                 ret = OGRERR_FAILURE;
    5159           0 :                 goto done;
    5160             :             }
    5161             :             else
    5162             :             {
    5163           0 :                 CPLErrorReset();
    5164           0 :                 ret = OGRERR_NONE;
    5165             :             }
    5166             :         }
    5167          12 :         if (!x_geom)
    5168             :         {
    5169           0 :             continue;
    5170             :         }
    5171             : 
    5172             :         OGRGeometryUniquePtr geom(
    5173             :             x_geom
    5174          12 :                 ->clone());  // this will be the geometry of the result feature
    5175             :         // incrementally erase y from geom
    5176          19 :         for (auto &&y : pLayerMethod)
    5177             :         {
    5178           9 :             OGRGeometry *y_geom = y->GetGeometryRef();
    5179           9 :             if (!y_geom)
    5180           0 :                 continue;
    5181           9 :             CPLErrorReset();
    5182           9 :             OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
    5183           9 :             if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
    5184             :             {
    5185           0 :                 if (!bSkipFailures)
    5186             :                 {
    5187           0 :                     ret = OGRERR_FAILURE;
    5188           0 :                     goto done;
    5189             :                 }
    5190             :                 else
    5191             :                 {
    5192           0 :                     CPLErrorReset();
    5193           0 :                     ret = OGRERR_NONE;
    5194             :                 }
    5195             :             }
    5196             :             else
    5197             :             {
    5198           9 :                 geom.swap(geom_new);
    5199           9 :                 if (geom->IsEmpty())
    5200             :                 {
    5201           2 :                     break;
    5202             :                 }
    5203             :             }
    5204             :         }
    5205             : 
    5206             :         // add a new feature if there is remaining area
    5207          12 :         if (!geom->IsEmpty())
    5208             :         {
    5209          10 :             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
    5210          10 :             z->SetFieldsFrom(x.get(), mapInput);
    5211          10 :             if (bPromoteToMulti)
    5212           4 :                 geom.reset(promote_to_multi(geom.release()));
    5213          10 :             z->SetGeometryDirectly(geom.release());
    5214          10 :             ret = pLayerResult->CreateFeature(z.get());
    5215          10 :             if (ret != OGRERR_NONE)
    5216             :             {
    5217           0 :                 if (!bSkipFailures)
    5218             :                 {
    5219           0 :                     goto done;
    5220             :                 }
    5221             :                 else
    5222             :                 {
    5223           0 :                     CPLErrorReset();
    5224           0 :                     ret = OGRERR_NONE;
    5225             :                 }
    5226             :             }
    5227             :         }
    5228             :     }
    5229           6 :     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
    5230             :     {
    5231           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    5232           0 :         ret = OGRERR_FAILURE;
    5233           0 :         goto done;
    5234             :     }
    5235           6 : done:
    5236             :     // release resources
    5237           6 :     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
    5238           6 :     if (pGeometryMethodFilter)
    5239           0 :         delete pGeometryMethodFilter;
    5240           6 :     if (mapInput)
    5241           5 :         VSIFree(mapInput);
    5242           6 :     return ret;
    5243             : }
    5244             : 
    5245             : /************************************************************************/
    5246             : /*                           OGR_L_Erase()                              */
    5247             : /************************************************************************/
    5248             : 
    5249             : /**
    5250             :  * \brief Remove areas that are covered by the method layer.
    5251             :  *
    5252             :  * The result layer contains features whose geometries represent areas
    5253             :  * that are in the input layer but not in the method layer. The
    5254             :  * features in the result layer have attributes from the input
    5255             :  * layer. The schema of the result layer can be set by the user or, if
    5256             :  * it is empty, is initialized to contain all fields in the input
    5257             :  * layer.
    5258             :  *
    5259             :  * \note For best performance use the minimum amount of features in
    5260             :  * the method layer and copy it into a memory layer.
    5261             :  *
    5262             :  * \note This method relies on GEOS support. Do not use unless the
    5263             :  * GEOS support is compiled in.
    5264             :  *
    5265             :  * The recognized list of options is :
    5266             :  * <ul>
    5267             :  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
    5268             :  *     feature could not be inserted or a GEOS call failed.
    5269             :  * </li>
    5270             :  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
    5271             :  *     into MultiPolygons, LineStrings to MultiLineStrings or
    5272             :  *     Points to MultiPoints (only since GDAL 3.9.2 for the later)
    5273             :  * </li>
    5274             :  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
    5275             :  *     will be created from the fields of the input layer.
    5276             :  * </li>
    5277             :  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
    5278             :  *     will be created from the fields of the method layer.
    5279             :  * </li>
    5280             :  * </ul>
    5281             :  *
    5282             :  * This function is the same as the C++ method OGRLayer::Erase().
    5283             :  *
    5284             :  * @param pLayerInput the input layer. Should not be NULL.
    5285             :  *
    5286             :  * @param pLayerMethod the method layer. Should not be NULL.
    5287             :  *
    5288             :  * @param pLayerResult the layer where the features resulting from the
    5289             :  * operation are inserted. Should not be NULL. See above the note
    5290             :  * about the schema.
    5291             :  *
    5292             :  * @param papszOptions NULL terminated list of options (may be NULL).
    5293             :  *
    5294             :  * @param pfnProgress a GDALProgressFunc() compatible callback function for
    5295             :  * reporting progress or NULL.
    5296             :  *
    5297             :  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
    5298             :  *
    5299             :  * @return an error code if there was an error or the execution was
    5300             :  * interrupted, OGRERR_NONE otherwise.
    5301             :  *
    5302             :  * @note The first geometry field is always used.
    5303             :  *
    5304             :  * @since OGR 1.10
    5305             :  */
    5306             : 
    5307           6 : OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
    5308             :                    OGRLayerH pLayerResult, char **papszOptions,
    5309             :                    GDALProgressFunc pfnProgress, void *pProgressArg)
    5310             : 
    5311             : {
    5312           6 :     VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    5313           6 :     VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    5314           6 :     VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
    5315             : 
    5316             :     return OGRLayer::FromHandle(pLayerInput)
    5317           6 :         ->Erase(OGRLayer::FromHandle(pLayerMethod),
    5318             :                 OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
    5319           6 :                 pProgressArg);
    5320             : }
    5321             : 
    5322             : /************************************************************************/
    5323             : /*                  OGRLayer::FeatureIterator::Private                  */
    5324             : /************************************************************************/
    5325             : 
    5326             : struct OGRLayer::FeatureIterator::Private
    5327             : {
    5328             :     CPL_DISALLOW_COPY_ASSIGN(Private)
    5329       35932 :     Private() = default;
    5330             : 
    5331             :     OGRFeatureUniquePtr m_poFeature{};
    5332             :     OGRLayer *m_poLayer = nullptr;
    5333             :     bool m_bError = false;
    5334             :     bool m_bEOF = true;
    5335             : };
    5336             : 
    5337             : /************************************************************************/
    5338             : /*                OGRLayer::FeatureIterator::FeatureIterator()          */
    5339             : /************************************************************************/
    5340             : 
    5341       35932 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
    5342       35932 :     : m_poPrivate(new OGRLayer::FeatureIterator::Private())
    5343             : {
    5344       35932 :     m_poPrivate->m_poLayer = poLayer;
    5345       35932 :     if (bStart)
    5346             :     {
    5347       17966 :         if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
    5348             :         {
    5349           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    5350             :                      "Only one feature iterator can be "
    5351             :                      "active at a time");
    5352           1 :             m_poPrivate->m_bError = true;
    5353             :         }
    5354             :         else
    5355             :         {
    5356       17965 :             m_poPrivate->m_poLayer->ResetReading();
    5357       35930 :             m_poPrivate->m_poFeature.reset(
    5358       17965 :                 m_poPrivate->m_poLayer->GetNextFeature());
    5359       17965 :             m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
    5360       17965 :             m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
    5361             :         }
    5362             :     }
    5363       35932 : }
    5364             : 
    5365             : /************************************************************************/
    5366             : /*               ~OGRLayer::FeatureIterator::FeatureIterator()          */
    5367             : /************************************************************************/
    5368             : 
    5369       35932 : OGRLayer::FeatureIterator::~FeatureIterator()
    5370             : {
    5371       35932 :     if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
    5372       35931 :         m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
    5373       35932 : }
    5374             : 
    5375             : /************************************************************************/
    5376             : /*                              operator*()                             */
    5377             : /************************************************************************/
    5378             : 
    5379      154192 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
    5380             : {
    5381      154192 :     return m_poPrivate->m_poFeature;
    5382             : }
    5383             : 
    5384             : /************************************************************************/
    5385             : /*                              operator++()                            */
    5386             : /************************************************************************/
    5387             : 
    5388      153511 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
    5389             : {
    5390      153511 :     m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
    5391      153511 :     m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
    5392      153511 :     return *this;
    5393             : }
    5394             : 
    5395             : /************************************************************************/
    5396             : /*                             operator!=()                             */
    5397             : /************************************************************************/
    5398             : 
    5399      171477 : bool OGRLayer::FeatureIterator::operator!=(
    5400             :     const OGRLayer::FeatureIterator &it) const
    5401             : {
    5402      171477 :     return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
    5403             : }
    5404             : 
    5405             : /************************************************************************/
    5406             : /*                                 begin()                              */
    5407             : /************************************************************************/
    5408             : 
    5409       17966 : OGRLayer::FeatureIterator OGRLayer::begin()
    5410             : {
    5411       17966 :     return {this, true};
    5412             : }
    5413             : 
    5414             : /************************************************************************/
    5415             : /*                                  end()                               */
    5416             : /************************************************************************/
    5417             : 
    5418       17966 : OGRLayer::FeatureIterator OGRLayer::end()
    5419             : {
    5420       17966 :     return {this, false};
    5421             : }
    5422             : 
    5423             : /************************************************************************/
    5424             : /*                     OGRLayer::GetGeometryTypes()                     */
    5425             : /************************************************************************/
    5426             : 
    5427             : /** \brief Get actual geometry types found in features.
    5428             :  *
    5429             :  * This method iterates over features to retrieve their geometry types. This
    5430             :  * is mostly useful for layers that report a wkbUnknown geometry type with
    5431             :  * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
    5432             :  *
    5433             :  * By default this method returns an array of nEntryCount entries with each
    5434             :  * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
    5435             :  * number of features (in OGRGeometryTypeCounter::nCount).
    5436             :  * Features without geometries are reported as eGeomType == wkbNone.
    5437             :  *
    5438             :  * The nFlagsGGT parameter can be a combination (with binary or operator) of the
    5439             :  * following hints:
    5440             :  * <ul>
    5441             :  * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
    5442             :  * matter, not the number of features per geometry type. Consequently the value
    5443             :  * of OGRGeometryTypeCounter::nCount should be ignored.</li>
    5444             :  * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
    5445             :  * iterating over features as soon as 2 different geometry types (not counting
    5446             :  * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
    5447             :  * should be ignored (zero might be systematically reported by some
    5448             :  * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
    5449             :  * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
    5450             :  * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
    5451             :  * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
    5452             :  * geometries.</li>
    5453             :  * </ul>
    5454             :  *
    5455             :  * If the layer has no features, a non-NULL returned array with nEntryCount == 0
    5456             :  * will be returned.
    5457             :  *
    5458             :  * Spatial and/or attribute filters will be taken into account.
    5459             :  *
    5460             :  * This method will error out on a layer without geometry fields
    5461             :  * (GetGeomType() == wkbNone).
    5462             :  *
    5463             :  * A cancellation callback may be provided. The progress percentage it is called
    5464             :  * with is not relevant. The callback should return TRUE if processing should go
    5465             :  * on, or FALSE if it should be interrupted.
    5466             :  *
    5467             :  * @param iGeomField Geometry field index.
    5468             :  * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
    5469             :  *                  OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
    5470             :  * @param[out] nEntryCountOut Number of entries in the returned array.
    5471             :  * @param pfnProgress Cancellation callback. May be NULL.
    5472             :  * @param pProgressData User data for the cancellation callback. May be NULL.
    5473             :  * @return an array of nEntryCount that must be freed with CPLFree(),
    5474             :  *         or NULL in case of error
    5475             :  * @since GDAL 3.6
    5476             :  */
    5477             : OGRGeometryTypeCounter *
    5478          12 : OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
    5479             :                            GDALProgressFunc pfnProgress, void *pProgressData)
    5480             : {
    5481          12 :     OGRFeatureDefn *poDefn = GetLayerDefn();
    5482          12 :     const int nGeomFieldCount = poDefn->GetGeomFieldCount();
    5483          12 :     if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
    5484             :     {
    5485           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
    5486           1 :         nEntryCountOut = 0;
    5487           1 :         return nullptr;
    5488             :     }
    5489             : 
    5490             :     // Ignore all fields but the geometry one of interest
    5491          22 :     CPLStringList aosIgnoredFieldsRestore;
    5492          22 :     CPLStringList aosIgnoredFields;
    5493          11 :     const int nFieldCount = poDefn->GetFieldCount();
    5494          33 :     for (int iField = 0; iField < nFieldCount; iField++)
    5495             :     {
    5496          22 :         const auto poFieldDefn = poDefn->GetFieldDefn(iField);
    5497          22 :         const char *pszName = poFieldDefn->GetNameRef();
    5498          22 :         if (poFieldDefn->IsIgnored())
    5499          10 :             aosIgnoredFieldsRestore.AddString(pszName);
    5500          22 :         if (iField != iGeomField)
    5501          11 :             aosIgnoredFields.AddString(pszName);
    5502             :     }
    5503          33 :     for (int iField = 0; iField < nGeomFieldCount; iField++)
    5504             :     {
    5505          22 :         const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
    5506          22 :         const char *pszName = poFieldDefn->GetNameRef();
    5507          22 :         if (poFieldDefn->IsIgnored())
    5508          10 :             aosIgnoredFieldsRestore.AddString(pszName);
    5509          22 :         if (iField != iGeomField)
    5510          11 :             aosIgnoredFields.AddString(pszName);
    5511             :     }
    5512          11 :     if (poDefn->IsStyleIgnored())
    5513           0 :         aosIgnoredFieldsRestore.AddString("OGR_STYLE");
    5514          11 :     aosIgnoredFields.AddString("OGR_STYLE");
    5515          11 :     SetIgnoredFields(aosIgnoredFields.List());
    5516             : 
    5517             :     // Iterate over features
    5518          22 :     std::map<OGRwkbGeometryType, int64_t> oMapCount;
    5519          22 :     std::set<OGRwkbGeometryType> oSetNotNull;
    5520          11 :     const bool bGeomCollectionZTInZ =
    5521          11 :         (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
    5522          11 :     const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
    5523          11 :     if (pfnProgress == GDALDummyProgress)
    5524           0 :         pfnProgress = nullptr;
    5525          11 :     bool bInterrupted = false;
    5526          47 :     for (auto &&poFeature : *this)
    5527             :     {
    5528          36 :         const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
    5529          36 :         if (poGeom == nullptr)
    5530             :         {
    5531          18 :             ++oMapCount[wkbNone];
    5532             :         }
    5533             :         else
    5534             :         {
    5535          18 :             auto eGeomType = poGeom->getGeometryType();
    5536          18 :             if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
    5537             :             {
    5538           1 :                 const auto poGC = poGeom->toGeometryCollection();
    5539           1 :                 if (poGC->getNumGeometries() > 0)
    5540             :                 {
    5541             :                     auto eSubGeomType =
    5542           1 :                         poGC->getGeometryRef(0)->getGeometryType();
    5543           1 :                     if (eSubGeomType == wkbTINZ)
    5544           1 :                         eGeomType = wkbTINZ;
    5545             :                 }
    5546             :             }
    5547          18 :             ++oMapCount[eGeomType];
    5548          18 :             if (bStopIfMixed)
    5549             :             {
    5550           4 :                 oSetNotNull.insert(eGeomType);
    5551           4 :                 if (oSetNotNull.size() == 2)
    5552           2 :                     break;
    5553             :             }
    5554             :         }
    5555          34 :         if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
    5556             :         {
    5557           1 :             bInterrupted = true;
    5558           1 :             break;
    5559             :         }
    5560             :     }
    5561             : 
    5562             :     // Restore ignore fields state
    5563          11 :     SetIgnoredFields(aosIgnoredFieldsRestore.List());
    5564             : 
    5565          11 :     if (bInterrupted)
    5566             :     {
    5567           1 :         nEntryCountOut = 0;
    5568           1 :         return nullptr;
    5569             :     }
    5570             : 
    5571             :     // Format result
    5572          10 :     nEntryCountOut = static_cast<int>(oMapCount.size());
    5573             :     OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
    5574          10 :         CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
    5575          10 :     int i = 0;
    5576          37 :     for (const auto &oIter : oMapCount)
    5577             :     {
    5578          27 :         pasRet[i].eGeomType = oIter.first;
    5579          27 :         pasRet[i].nCount = oIter.second;
    5580          27 :         ++i;
    5581             :     }
    5582          10 :     return pasRet;
    5583             : }
    5584             : 
    5585             : /************************************************************************/
    5586             : /*                      OGR_L_GetGeometryTypes()                        */
    5587             : /************************************************************************/
    5588             : 
    5589             : /** \brief Get actual geometry types found in features.
    5590             :  *
    5591             :  * See OGRLayer::GetGeometryTypes() for details.
    5592             :  *
    5593             :  * @param hLayer Layer.
    5594             :  * @param iGeomField Geometry field index.
    5595             :  * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
    5596             :  *               OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
    5597             :  * @param[out] pnEntryCount Pointer to the number of entries in the returned
    5598             :  *                          array. Must not be NULL.
    5599             :  * @param pfnProgress Cancellation callback. May be NULL.
    5600             :  * @param pProgressData User data for the cancellation callback. May be NULL.
    5601             :  * @return an array of *pnEntryCount that must be freed with CPLFree(),
    5602             :  *         or NULL in case of error
    5603             :  * @since GDAL 3.6
    5604             :  */
    5605          54 : OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
    5606             :                                                int nFlags, int *pnEntryCount,
    5607             :                                                GDALProgressFunc pfnProgress,
    5608             :                                                void *pProgressData)
    5609             : {
    5610          54 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
    5611          54 :     VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
    5612             : 
    5613         108 :     return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
    5614          54 :         iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
    5615             : }
    5616             : 
    5617             : /************************************************************************/
    5618             : /*                    OGRLayer::GetSupportedSRSList()                   */
    5619             : /************************************************************************/
    5620             : 
    5621             : /** \brief Get the list of SRS supported.
    5622             :  *
    5623             :  * The base implementation of this method will return an empty list. Some
    5624             :  * drivers (OAPIF, WFS) may return a non-empty list.
    5625             :  *
    5626             :  * One of the SRS returned may be passed to SetActiveSRS() to change the
    5627             :  * active SRS.
    5628             :  *
    5629             :  * @param iGeomField Geometry field index.
    5630             :  * @return list of supported SRS.
    5631             :  * @since GDAL 3.7
    5632             :  */
    5633             : const OGRLayer::GetSupportedSRSListRetType &
    5634         161 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
    5635             : {
    5636         161 :     static OGRLayer::GetSupportedSRSListRetType empty;
    5637         161 :     return empty;
    5638             : }
    5639             : 
    5640             : /************************************************************************/
    5641             : /*                    OGR_L_GetSupportedSRSList()                       */
    5642             : /************************************************************************/
    5643             : 
    5644             : /** \brief Get the list of SRS supported.
    5645             :  *
    5646             :  * The base implementation of this method will return an empty list. Some
    5647             :  * drivers (OAPIF, WFS) may return a non-empty list.
    5648             :  *
    5649             :  * One of the SRS returned may be passed to SetActiveSRS() to change the
    5650             :  * active SRS.
    5651             :  *
    5652             :  * @param hLayer Layer.
    5653             :  * @param iGeomField Geometry field index.
    5654             :  * @param[out] pnCount Number of values in returned array. Must not be null.
    5655             :  * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
    5656             :  * nullptr
    5657             :  * @since GDAL 3.7
    5658             :  */
    5659           4 : OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
    5660             :                                                 int iGeomField, int *pnCount)
    5661             : {
    5662           4 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
    5663           4 :     VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
    5664             : 
    5665             :     const auto &srsList =
    5666           4 :         OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
    5667           4 :     *pnCount = static_cast<int>(srsList.size());
    5668           4 :     if (srsList.empty())
    5669             :     {
    5670           2 :         return nullptr;
    5671             :     }
    5672             :     OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
    5673           2 :         CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
    5674           2 :     size_t i = 0;
    5675           7 :     for (const auto &poSRS : srsList)
    5676             :     {
    5677           5 :         poSRS->Reference();
    5678           5 :         pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
    5679           5 :         ++i;
    5680             :     }
    5681           2 :     pahRet[i] = nullptr;
    5682           2 :     return pahRet;
    5683             : }
    5684             : 
    5685             : /************************************************************************/
    5686             : /*                       OGRLayer::SetActiveSRS()                       */
    5687             : /************************************************************************/
    5688             : 
    5689             : /** \brief Change the active SRS.
    5690             :  *
    5691             :  * The passed SRS must be in the list returned by GetSupportedSRSList()
    5692             :  * (the actual pointer may be different, but should be tested as identical
    5693             :  * with OGRSpatialReference::IsSame()).
    5694             :  *
    5695             :  * Changing the active SRS affects:
    5696             :  * <ul>
    5697             :  * <li>the SRS in which geometries of returned features are expressed,</li>
    5698             :  * <li>the SRS in which geometries of passed features (CreateFeature(),
    5699             :  * SetFeature()) are expressed,</li>
    5700             :  * <li>the SRS returned by GetSpatialRef() and
    5701             :  * GetGeomFieldDefn()->GetSpatialRef(),</li>
    5702             :  * <li>the SRS used to interpret SetSpatialFilter() values.</li>
    5703             :  * </ul>
    5704             :  * This also resets feature reading and the spatial filter.
    5705             :  * Note however that this does not modify the storage SRS of the features of
    5706             :  * geometries. Said otherwise, this setting is volatile and has no persistent
    5707             :  * effects after dataset reopening.
    5708             :  *
    5709             :  * @param iGeomField Geometry field index.
    5710             :  * @param poSRS SRS to use
    5711             :  * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
    5712             :  *         the passed SRS is not in GetSupportedSRSList()
    5713             :  * @since GDAL 3.7
    5714             :  */
    5715           1 : OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
    5716             :                               CPL_UNUSED const OGRSpatialReference *poSRS)
    5717             : {
    5718           1 :     return OGRERR_FAILURE;
    5719             : }
    5720             : 
    5721             : /************************************************************************/
    5722             : /*                         OGR_L_SetActiveSRS()                         */
    5723             : /************************************************************************/
    5724             : 
    5725             : /** \brief Change the active SRS.
    5726             :  *
    5727             :  * The passed SRS must be in the list returned by GetSupportedSRSList()
    5728             :  * (the actual pointer may be different, but should be tested as identical
    5729             :  * with OGRSpatialReference::IsSame()).
    5730             :  *
    5731             :  * Changing the active SRS affects:
    5732             :  * <ul>
    5733             :  * <li>the SRS in which geometries of returned features are expressed,</li>
    5734             :  * <li>the SRS in which geometries of passed features (CreateFeature(),
    5735             :  * SetFeature()) are expressed,</li>
    5736             :  * <li>the SRS returned by GetSpatialRef() and
    5737             :  * GetGeomFieldDefn()->GetSpatialRef(),</li>
    5738             :  * <li>the SRS used to interpret SetSpatialFilter() values.</li>
    5739             :  * </ul>
    5740             :  * This also resets feature reading and the spatial filter.
    5741             :  * Note however that this does not modify the storage SRS of the features of
    5742             :  * geometries. Said otherwise, this setting is volatile and has no persistent
    5743             :  * effects after dataset reopening.
    5744             :  *
    5745             :  * @param hLayer Layer.
    5746             :  * @param iGeomField Geometry field index.
    5747             :  * @param hSRS SRS to use
    5748             :  * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
    5749             :  *         the passed SRS is not in GetSupportedSRSList().
    5750             :  * @since GDAL 3.7
    5751             :  */
    5752           9 : OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
    5753             :                           OGRSpatialReferenceH hSRS)
    5754             : {
    5755           9 :     VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
    5756          18 :     return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
    5757           9 :         iGeomField, OGRSpatialReference::FromHandle(hSRS));
    5758             : }
    5759             : 
    5760             : /************************************************************************/
    5761             : /*                             GetDataset()                             */
    5762             : /************************************************************************/
    5763             : 
    5764             : /** Return the dataset associated with this layer.
    5765             :  *
    5766             :  * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
    5767             :  * have CreateLayer() capability. It may not be implemented in read-only
    5768             :  * drivers or out-of-tree drivers.
    5769             :  *
    5770             :  * It is currently only used by the GetRecordBatchSchema()
    5771             :  * method to retrieve the field domain associated with a field, to fill the
    5772             :  * dictionary field of a struct ArrowSchema.
    5773             :  * It is also used by CreateFieldFromArrowSchema() to determine which field
    5774             :  * types and subtypes are supported by the layer, by inspecting the driver
    5775             :  * metadata, and potentially use fallback types when needed.
    5776             :  *
    5777             :  * This method is the same as the C function OGR_L_GetDataset().
    5778             :  *
    5779             :  * @return dataset, or nullptr when unknown.
    5780             :  * @since GDAL 3.6
    5781             :  */
    5782           0 : GDALDataset *OGRLayer::GetDataset()
    5783             : {
    5784           0 :     return nullptr;
    5785             : }
    5786             : 
    5787             : /************************************************************************/
    5788             : /*                          OGR_L_GetDataset()                          */
    5789             : /************************************************************************/
    5790             : 
    5791             : /** Return the dataset associated with this layer.
    5792             :  *
    5793             :  * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
    5794             :  * have CreateLayer() capability. It may not be implemented in read-only
    5795             :  * drivers or out-of-tree drivers.
    5796             :  *
    5797             :  * It is currently only used by the GetRecordBatchSchema()
    5798             :  * method to retrieve the field domain associated with a field, to fill the
    5799             :  * dictionary field of a struct ArrowSchema.
    5800             :  * It is also used by CreateFieldFromArrowSchema() to determine which field
    5801             :  * types and subtypes are supported by the layer, by inspecting the driver
    5802             :  * metadata, and potentially use fallback types when needed.
    5803             :  *
    5804             :  * This function is the same as the C++ method OGRLayer::GetDataset().
    5805             :  *
    5806             :  * @return dataset, or nullptr when unknown.
    5807             :  * @since GDAL 3.9
    5808             :  */
    5809         268 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
    5810             : {
    5811         268 :     VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
    5812         268 :     return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
    5813             : }

Generated by: LCOV version 1.14