LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrunionlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 628 737 85.2 %
Date: 2025-11-08 22:13:33 Functions: 34 36 94.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRUnionLayer class
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2012-2014, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef DOXYGEN_SKIP
      14             : 
      15             : #include "ogrunionlayer.h"
      16             : #include "ogrwarpedlayer.h"
      17             : #include "ogr_p.h"
      18             : 
      19             : #include <limits>
      20             : 
      21             : /************************************************************************/
      22             : /*                      OGRUnionLayerGeomFieldDefn()                    */
      23             : /************************************************************************/
      24             : 
      25          21 : OGRUnionLayerGeomFieldDefn::OGRUnionLayerGeomFieldDefn(const char *pszNameIn,
      26          21 :                                                        OGRwkbGeometryType eType)
      27          21 :     : OGRGeomFieldDefn(pszNameIn, eType)
      28             : {
      29          21 : }
      30             : 
      31             : /************************************************************************/
      32             : /*                      OGRUnionLayerGeomFieldDefn()                    */
      33             : /************************************************************************/
      34             : 
      35         117 : OGRUnionLayerGeomFieldDefn::OGRUnionLayerGeomFieldDefn(
      36         117 :     const OGRGeomFieldDefn *poSrc)
      37         117 :     : OGRGeomFieldDefn(poSrc->GetNameRef(), poSrc->GetType())
      38             : {
      39         117 :     SetSpatialRef(poSrc->GetSpatialRef());
      40         117 : }
      41             : 
      42             : /************************************************************************/
      43             : /*                      OGRUnionLayerGeomFieldDefn()                    */
      44             : /************************************************************************/
      45             : 
      46          31 : OGRUnionLayerGeomFieldDefn::OGRUnionLayerGeomFieldDefn(
      47          31 :     const OGRUnionLayerGeomFieldDefn *poSrc)
      48             :     : OGRGeomFieldDefn(poSrc->GetNameRef(), poSrc->GetType()),
      49          31 :       bGeomTypeSet(poSrc->bGeomTypeSet), bSRSSet(poSrc->bSRSSet)
      50             : {
      51          31 :     SetSpatialRef(poSrc->GetSpatialRef());
      52          31 :     sStaticEnvelope = poSrc->sStaticEnvelope;
      53          31 : }
      54             : 
      55             : /************************************************************************/
      56             : /*                     ~OGRUnionLayerGeomFieldDefn()                    */
      57             : /************************************************************************/
      58             : 
      59         338 : OGRUnionLayerGeomFieldDefn::~OGRUnionLayerGeomFieldDefn()
      60             : {
      61         338 : }
      62             : 
      63             : /************************************************************************/
      64             : /*                          OGRUnionLayer()                             */
      65             : /************************************************************************/
      66             : 
      67             : // cppcheck-suppress uninitMemberVar
      68         126 : OGRUnionLayer::OGRUnionLayer(const char *pszName, int nSrcLayersIn,
      69             :                              OGRLayer **papoSrcLayersIn,
      70         126 :                              int bTakeLayerOwnership)
      71         126 :     : osName(pszName)
      72             : {
      73         126 :     CPLAssert(nSrcLayersIn > 0);
      74             : 
      75         126 :     SetDescription(pszName);
      76             : 
      77         356 :     for (int i = 0; i < nSrcLayersIn; ++i)
      78             :     {
      79         230 :         m_apoSrcLayers.emplace_back(papoSrcLayersIn[i],
      80         230 :                                     CPL_TO_BOOL(bTakeLayerOwnership));
      81             :     }
      82         126 :     CPLFree(papoSrcLayersIn);
      83         126 : }
      84             : 
      85             : /************************************************************************/
      86             : /*                         ~OGRUnionLayer()                             */
      87             : /************************************************************************/
      88             : 
      89         252 : OGRUnionLayer::~OGRUnionLayer()
      90             : {
      91         126 :     m_apoSrcLayers.clear();
      92             : 
      93         158 :     for (int i = 0; i < nFields; i++)
      94          32 :         delete papoFields[i];
      95         126 :     CPLFree(papoFields);
      96         149 :     for (int i = 0; i < nGeomFields; i++)
      97          23 :         delete papoGeomFields[i];
      98         126 :     CPLFree(papoGeomFields);
      99             : 
     100         126 :     CPLFree(pszAttributeFilter);
     101         126 :     CPLFree(panMap);
     102             : 
     103         126 :     if (poFeatureDefn)
     104         110 :         poFeatureDefn->Release();
     105         126 :     if (poGlobalSRS != nullptr)
     106          36 :         const_cast<OGRSpatialReference *>(poGlobalSRS)->Release();
     107         252 : }
     108             : 
     109             : /************************************************************************/
     110             : /*                              SetFields()                             */
     111             : /************************************************************************/
     112             : 
     113         120 : void OGRUnionLayer::SetFields(FieldUnionStrategy eFieldStrategyIn,
     114             :                               int nFieldsIn, OGRFieldDefn **papoFieldsIn,
     115             :                               int nGeomFieldsIn,
     116             :                               OGRUnionLayerGeomFieldDefn **papoGeomFieldsIn)
     117             : {
     118         120 :     CPLAssert(nFields == 0);
     119         120 :     CPLAssert(poFeatureDefn == nullptr);
     120             : 
     121         120 :     eFieldStrategy = eFieldStrategyIn;
     122         120 :     if (nFieldsIn)
     123             :     {
     124           2 :         nFields = nFieldsIn;
     125           2 :         papoFields = static_cast<OGRFieldDefn **>(
     126           2 :             CPLMalloc(nFields * sizeof(OGRFieldDefn *)));
     127          34 :         for (int i = 0; i < nFields; i++)
     128          32 :             papoFields[i] = new OGRFieldDefn(papoFieldsIn[i]);
     129             :     }
     130         120 :     nGeomFields = nGeomFieldsIn;
     131         120 :     if (nGeomFields > 0)
     132             :     {
     133          17 :         papoGeomFields = static_cast<OGRUnionLayerGeomFieldDefn **>(
     134          17 :             CPLMalloc(nGeomFields * sizeof(OGRUnionLayerGeomFieldDefn *)));
     135          40 :         for (int i = 0; i < nGeomFields; i++)
     136          23 :             papoGeomFields[i] =
     137          23 :                 new OGRUnionLayerGeomFieldDefn(papoGeomFieldsIn[i]);
     138             :     }
     139         120 : }
     140             : 
     141             : /************************************************************************/
     142             : /*                        SetSourceLayerFieldName()                     */
     143             : /************************************************************************/
     144             : 
     145          92 : void OGRUnionLayer::SetSourceLayerFieldName(const char *pszSourceLayerFieldName)
     146             : {
     147          92 :     CPLAssert(poFeatureDefn == nullptr);
     148             : 
     149          92 :     CPLAssert(osSourceLayerFieldName.empty());
     150          92 :     if (pszSourceLayerFieldName != nullptr)
     151          17 :         osSourceLayerFieldName = pszSourceLayerFieldName;
     152          92 : }
     153             : 
     154             : /************************************************************************/
     155             : /*                           SetPreserveSrcFID()                        */
     156             : /************************************************************************/
     157             : 
     158          85 : void OGRUnionLayer::SetPreserveSrcFID(int bPreserveSrcFIDIn)
     159             : {
     160          85 :     CPLAssert(poFeatureDefn == nullptr);
     161             : 
     162          85 :     bPreserveSrcFID = bPreserveSrcFIDIn;
     163          85 : }
     164             : 
     165             : /************************************************************************/
     166             : /*                          SetFeatureCount()                           */
     167             : /************************************************************************/
     168             : 
     169           9 : void OGRUnionLayer::SetFeatureCount(int nFeatureCountIn)
     170             : {
     171           9 :     CPLAssert(poFeatureDefn == nullptr);
     172             : 
     173           9 :     nFeatureCount = nFeatureCountIn;
     174           9 : }
     175             : 
     176             : /************************************************************************/
     177             : /*                         MergeFieldDefn()                             */
     178             : /************************************************************************/
     179             : 
     180          73 : static void MergeFieldDefn(OGRFieldDefn *poFieldDefn,
     181             :                            const OGRFieldDefn *poSrcFieldDefn)
     182             : {
     183          73 :     if (poFieldDefn->GetType() != poSrcFieldDefn->GetType())
     184             :     {
     185          21 :         if (poSrcFieldDefn->GetType() == OFTReal &&
     186           0 :             (poFieldDefn->GetType() == OFTInteger ||
     187           0 :              poFieldDefn->GetType() == OFTInteger64))
     188           0 :             poFieldDefn->SetType(OFTReal);
     189          21 :         if (poFieldDefn->GetType() == OFTReal &&
     190           0 :             (poSrcFieldDefn->GetType() == OFTInteger ||
     191           0 :              poSrcFieldDefn->GetType() == OFTInteger64))
     192           0 :             poFieldDefn->SetType(OFTReal);
     193          38 :         else if (poSrcFieldDefn->GetType() == OFTInteger64 &&
     194          17 :                  poFieldDefn->GetType() == OFTInteger)
     195          17 :             poFieldDefn->SetType(OFTInteger64);
     196           4 :         else if (poFieldDefn->GetType() == OFTInteger64 &&
     197           0 :                  poSrcFieldDefn->GetType() == OFTInteger)
     198           0 :             poFieldDefn->SetType(OFTInteger64);
     199             :         else
     200           4 :             poFieldDefn->SetType(OFTString);
     201             :     }
     202             : 
     203         121 :     if (poFieldDefn->GetWidth() != poSrcFieldDefn->GetWidth() ||
     204          48 :         poFieldDefn->GetPrecision() != poSrcFieldDefn->GetPrecision())
     205             :     {
     206          25 :         poFieldDefn->SetWidth(0);
     207          25 :         poFieldDefn->SetPrecision(0);
     208             :     }
     209          73 : }
     210             : 
     211             : /************************************************************************/
     212             : /*                             GetLayerDefn()                           */
     213             : /************************************************************************/
     214             : 
     215        5501 : const OGRFeatureDefn *OGRUnionLayer::GetLayerDefn() const
     216             : {
     217        5501 :     if (poFeatureDefn != nullptr)
     218        5391 :         return poFeatureDefn;
     219             : 
     220         110 :     poFeatureDefn = new OGRFeatureDefn(osName);
     221         110 :     poFeatureDefn->Reference();
     222         110 :     poFeatureDefn->SetGeomType(wkbNone);
     223             : 
     224         110 :     int iCompareFirstIndex = 0;
     225         110 :     if (!osSourceLayerFieldName.empty())
     226             :     {
     227          14 :         OGRFieldDefn oField(osSourceLayerFieldName, OFTString);
     228          14 :         poFeatureDefn->AddFieldDefn(&oField);
     229          14 :         iCompareFirstIndex = 1;
     230             :     }
     231             : 
     232         110 :     if (eFieldStrategy == FIELD_SPECIFIED)
     233             :     {
     234           4 :         for (int i = 0; i < nFields; i++)
     235           0 :             poFeatureDefn->AddFieldDefn(papoFields[i]);
     236          12 :         for (int i = 0; i < nGeomFields; i++)
     237             :         {
     238           8 :             poFeatureDefn->AddGeomFieldDefn(
     239           8 :                 std::make_unique<OGRUnionLayerGeomFieldDefn>(
     240           8 :                     papoGeomFields[i]));
     241             :             OGRUnionLayerGeomFieldDefn *poGeomFieldDefn =
     242           8 :                 cpl::down_cast<OGRUnionLayerGeomFieldDefn *>(
     243           8 :                     poFeatureDefn->GetGeomFieldDefn(i));
     244             : 
     245           8 :             if (poGeomFieldDefn->bGeomTypeSet == FALSE ||
     246           2 :                 poGeomFieldDefn->bSRSSet == FALSE)
     247             :             {
     248           8 :                 for (auto &oLayer : m_apoSrcLayers)
     249             :                 {
     250             :                     const OGRFeatureDefn *poSrcFeatureDefn =
     251           8 :                         oLayer->GetLayerDefn();
     252           8 :                     int nIndex = poSrcFeatureDefn->GetGeomFieldIndex(
     253           8 :                         poGeomFieldDefn->GetNameRef());
     254           8 :                     if (nIndex >= 0)
     255             :                     {
     256             :                         const OGRGeomFieldDefn *poSrcGeomFieldDefn =
     257           8 :                             poSrcFeatureDefn->GetGeomFieldDefn(nIndex);
     258           8 :                         if (poGeomFieldDefn->bGeomTypeSet == FALSE)
     259             :                         {
     260           6 :                             poGeomFieldDefn->bGeomTypeSet = TRUE;
     261           6 :                             poGeomFieldDefn->SetType(
     262             :                                 poSrcGeomFieldDefn->GetType());
     263             :                         }
     264           8 :                         if (poGeomFieldDefn->bSRSSet == FALSE)
     265             :                         {
     266           6 :                             poGeomFieldDefn->bSRSSet = TRUE;
     267           6 :                             poGeomFieldDefn->SetSpatialRef(
     268           6 :                                 poSrcGeomFieldDefn->GetSpatialRef());
     269           6 :                             if (i == 0 && poGlobalSRS == nullptr)
     270             :                             {
     271           4 :                                 poGlobalSRS =
     272           4 :                                     poSrcGeomFieldDefn->GetSpatialRef();
     273           4 :                                 if (poGlobalSRS != nullptr)
     274             :                                     const_cast<OGRSpatialReference *>(
     275           4 :                                         poGlobalSRS)
     276           4 :                                         ->Reference();
     277             :                             }
     278             :                         }
     279           8 :                         break;
     280             :                     }
     281             :                 }
     282             :             }
     283             :         }
     284             :     }
     285         106 :     else if (eFieldStrategy == FIELD_FROM_FIRST_LAYER)
     286             :     {
     287             :         const OGRFeatureDefn *poSrcFeatureDefn =
     288           4 :             m_apoSrcLayers[0]->GetLayerDefn();
     289           4 :         const int nSrcFieldCount = poSrcFeatureDefn->GetFieldCount();
     290          46 :         for (int i = 0; i < nSrcFieldCount; i++)
     291          42 :             poFeatureDefn->AddFieldDefn(poSrcFeatureDefn->GetFieldDefn(i));
     292           4 :         for (int i = 0;
     293          12 :              nGeomFields != -1 && i < poSrcFeatureDefn->GetGeomFieldCount();
     294             :              i++)
     295             :         {
     296             :             const OGRGeomFieldDefn *poFldDefn =
     297           8 :                 poSrcFeatureDefn->GetGeomFieldDefn(i);
     298           8 :             poFeatureDefn->AddGeomFieldDefn(
     299          16 :                 std::make_unique<OGRUnionLayerGeomFieldDefn>(poFldDefn));
     300             :         }
     301             :     }
     302         102 :     else if (eFieldStrategy == FIELD_UNION_ALL_LAYERS)
     303             :     {
     304          93 :         if (nGeomFields == 1)
     305             :         {
     306           0 :             poFeatureDefn->AddGeomFieldDefn(
     307           0 :                 std::make_unique<OGRUnionLayerGeomFieldDefn>(
     308           0 :                     papoGeomFields[0]));
     309             :         }
     310             : 
     311          93 :         int nDstFieldCount = 0;
     312         186 :         std::map<std::string, int> oMapDstFieldNameToIdx;
     313             : 
     314         261 :         for (auto &oLayer : m_apoSrcLayers)
     315             :         {
     316         168 :             const OGRFeatureDefn *poSrcFeatureDefn = oLayer->GetLayerDefn();
     317             : 
     318             :             /* Add any field that is found in the source layers */
     319         168 :             const int nSrcFieldCount = poSrcFeatureDefn->GetFieldCount();
     320         359 :             for (int i = 0; i < nSrcFieldCount; i++)
     321             :             {
     322             :                 const OGRFieldDefn *poSrcFieldDefn =
     323         191 :                     poSrcFeatureDefn->GetFieldDefn(i);
     324             :                 const auto oIter =
     325         191 :                     oMapDstFieldNameToIdx.find(poSrcFieldDefn->GetNameRef());
     326             :                 const int nIndex =
     327         191 :                     oIter == oMapDstFieldNameToIdx.end() ? -1 : oIter->second;
     328         191 :                 if (nIndex < 0)
     329             :                 {
     330         133 :                     oMapDstFieldNameToIdx[poSrcFieldDefn->GetNameRef()] =
     331             :                         nDstFieldCount;
     332         133 :                     nDstFieldCount++;
     333         133 :                     poFeatureDefn->AddFieldDefn(poSrcFieldDefn);
     334             :                 }
     335             :                 else
     336             :                 {
     337             :                     OGRFieldDefn *poFieldDefn =
     338          58 :                         poFeatureDefn->GetFieldDefn(nIndex);
     339          58 :                     MergeFieldDefn(poFieldDefn, poSrcFieldDefn);
     340             :                 }
     341             :             }
     342             : 
     343         327 :             for (int i = 0;
     344         327 :                  nGeomFields != -1 && i < poSrcFeatureDefn->GetGeomFieldCount();
     345             :                  i++)
     346             :             {
     347             :                 const OGRGeomFieldDefn *poSrcFieldDefn =
     348         159 :                     poSrcFeatureDefn->GetGeomFieldDefn(i);
     349         159 :                 int nIndex = poFeatureDefn->GetGeomFieldIndex(
     350         159 :                     poSrcFieldDefn->GetNameRef());
     351         159 :                 if (nIndex < 0)
     352             :                 {
     353          94 :                     poFeatureDefn->AddGeomFieldDefn(
     354          94 :                         std::make_unique<OGRUnionLayerGeomFieldDefn>(
     355          94 :                             poSrcFieldDefn));
     356          94 :                     if (poFeatureDefn->GetGeomFieldCount() == 1 &&
     357          94 :                         nGeomFields == 0 && GetSpatialRef() != nullptr)
     358             :                     {
     359             :                         OGRUnionLayerGeomFieldDefn *poGeomFieldDefn =
     360          29 :                             cpl::down_cast<OGRUnionLayerGeomFieldDefn *>(
     361          29 :                                 poFeatureDefn->GetGeomFieldDefn(0));
     362          29 :                         poGeomFieldDefn->bSRSSet = TRUE;
     363          29 :                         poGeomFieldDefn->SetSpatialRef(GetSpatialRef());
     364             :                     }
     365             :                 }
     366             :                 else
     367             :                 {
     368          65 :                     if (nIndex == 0 && nGeomFields == 1)
     369             :                     {
     370             :                         OGRUnionLayerGeomFieldDefn *poGeomFieldDefn =
     371           0 :                             cpl::down_cast<OGRUnionLayerGeomFieldDefn *>(
     372           0 :                                 poFeatureDefn->GetGeomFieldDefn(0));
     373           0 :                         if (poGeomFieldDefn->bGeomTypeSet == FALSE)
     374             :                         {
     375           0 :                             poGeomFieldDefn->bGeomTypeSet = TRUE;
     376           0 :                             poGeomFieldDefn->SetType(poSrcFieldDefn->GetType());
     377             :                         }
     378           0 :                         if (poGeomFieldDefn->bSRSSet == FALSE)
     379             :                         {
     380           0 :                             poGeomFieldDefn->bSRSSet = TRUE;
     381           0 :                             poGeomFieldDefn->SetSpatialRef(
     382           0 :                                 poSrcFieldDefn->GetSpatialRef());
     383             :                         }
     384             :                     }
     385             :                     /* TODO: merge type, SRS, extent ? */
     386             :                 }
     387             :             }
     388             :         }
     389             :     }
     390           9 :     else if (eFieldStrategy == FIELD_INTERSECTION_ALL_LAYERS)
     391             :     {
     392             :         const OGRFeatureDefn *poSrcFeatureDefn =
     393           9 :             m_apoSrcLayers[0]->GetLayerDefn();
     394          33 :         for (int i = 0; i < poSrcFeatureDefn->GetFieldCount(); i++)
     395          24 :             poFeatureDefn->AddFieldDefn(poSrcFeatureDefn->GetFieldDefn(i));
     396          22 :         for (int i = 0; i < poSrcFeatureDefn->GetGeomFieldCount(); i++)
     397             :         {
     398             :             const OGRGeomFieldDefn *poFldDefn =
     399          13 :                 poSrcFeatureDefn->GetGeomFieldDefn(i);
     400          13 :             poFeatureDefn->AddGeomFieldDefn(
     401          26 :                 std::make_unique<OGRUnionLayerGeomFieldDefn>(poFldDefn));
     402             :         }
     403             : 
     404             :         /* Remove any field that is not found in the source layers */
     405          18 :         for (int iLayer = 1; iLayer < static_cast<int>(m_apoSrcLayers.size());
     406             :              iLayer++)
     407             :         {
     408             :             const OGRFeatureDefn *l_poSrcFeatureDefn =
     409           9 :                 m_apoSrcLayers[iLayer]->GetLayerDefn();
     410          33 :             for (int i = iCompareFirstIndex; i < poFeatureDefn->GetFieldCount();
     411             :                  // No increment.
     412             :             )
     413             :             {
     414          24 :                 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     415          24 :                 int nSrcIndex = l_poSrcFeatureDefn->GetFieldIndex(
     416          24 :                     poFieldDefn->GetNameRef());
     417          24 :                 if (nSrcIndex < 0)
     418             :                 {
     419           9 :                     poFeatureDefn->DeleteFieldDefn(i);
     420             :                 }
     421             :                 else
     422             :                 {
     423             :                     const OGRFieldDefn *poSrcFieldDefn =
     424          15 :                         l_poSrcFeatureDefn->GetFieldDefn(nSrcIndex);
     425          15 :                     MergeFieldDefn(poFieldDefn, poSrcFieldDefn);
     426             : 
     427          15 :                     i++;
     428             :                 }
     429             :             }
     430          22 :             for (int i = 0; i < poFeatureDefn->GetGeomFieldCount();
     431             :                  // No increment.
     432             :             )
     433             :             {
     434             :                 const OGRGeomFieldDefn *poFieldDefn =
     435          13 :                     poFeatureDefn->GetGeomFieldDefn(i);
     436          13 :                 int nSrcIndex = l_poSrcFeatureDefn->GetGeomFieldIndex(
     437          13 :                     poFieldDefn->GetNameRef());
     438          13 :                 if (nSrcIndex < 0)
     439             :                 {
     440           2 :                     poFeatureDefn->DeleteGeomFieldDefn(i);
     441             :                 }
     442             :                 else
     443             :                 {
     444             :                     /* TODO: merge type, SRS, extent ? */
     445             : 
     446          11 :                     i++;
     447             :                 }
     448             :             }
     449             :         }
     450             :     }
     451             : 
     452         110 :     return poFeatureDefn;
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*                             GetGeomType()                            */
     457             : /************************************************************************/
     458             : 
     459          11 : OGRwkbGeometryType OGRUnionLayer::GetGeomType() const
     460             : {
     461          11 :     if (nGeomFields < 0)
     462           1 :         return wkbNone;
     463          10 :     if (nGeomFields >= 1 && papoGeomFields[0]->bGeomTypeSet)
     464             :     {
     465           2 :         return papoGeomFields[0]->GetType();
     466             :     }
     467             : 
     468           8 :     return OGRLayer::GetGeomType();
     469             : }
     470             : 
     471             : /************************************************************************/
     472             : /*                    SetSpatialFilterToSourceLayer()                   */
     473             : /************************************************************************/
     474             : 
     475        1024 : void OGRUnionLayer::SetSpatialFilterToSourceLayer(OGRLayer *poSrcLayer)
     476             : {
     477        2048 :     if (m_iGeomFieldFilter >= 0 &&
     478        1024 :         m_iGeomFieldFilter < GetLayerDefn()->GetGeomFieldCount())
     479             :     {
     480        1796 :         int iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
     481         898 :             GetLayerDefn()->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef());
     482         898 :         if (iSrcGeomField >= 0)
     483             :         {
     484         897 :             poSrcLayer->SetSpatialFilter(iSrcGeomField, m_poFilterGeom);
     485             :         }
     486             :         else
     487             :         {
     488           1 :             poSrcLayer->SetSpatialFilter(nullptr);
     489             :         }
     490             :     }
     491             :     else
     492             :     {
     493         126 :         poSrcLayer->SetSpatialFilter(nullptr);
     494             :     }
     495        1024 : }
     496             : 
     497             : /************************************************************************/
     498             : /*                        ConfigureActiveLayer()                        */
     499             : /************************************************************************/
     500             : 
     501         722 : void OGRUnionLayer::ConfigureActiveLayer()
     502             : {
     503         722 :     AutoWarpLayerIfNecessary(iCurLayer);
     504         722 :     ApplyAttributeFilterToSrcLayer(iCurLayer);
     505         722 :     SetSpatialFilterToSourceLayer(m_apoSrcLayers[iCurLayer].poLayer);
     506         722 :     m_apoSrcLayers[iCurLayer]->ResetReading();
     507             : 
     508             :     /* Establish map */
     509         722 :     GetLayerDefn();
     510             :     const OGRFeatureDefn *poSrcFeatureDefn =
     511         722 :         m_apoSrcLayers[iCurLayer]->GetLayerDefn();
     512         722 :     const int nSrcFieldCount = poSrcFeatureDefn->GetFieldCount();
     513         722 :     const int nDstFieldCount = poFeatureDefn->GetFieldCount();
     514             : 
     515        1444 :     std::map<std::string, int> oMapDstFieldNameToIdx;
     516        2937 :     for (int i = 0; i < nDstFieldCount; i++)
     517             :     {
     518        2215 :         const OGRFieldDefn *poDstFieldDefn = poFeatureDefn->GetFieldDefn(i);
     519        2215 :         oMapDstFieldNameToIdx[poDstFieldDefn->GetNameRef()] = i;
     520             :     }
     521             : 
     522         722 :     CPLFree(panMap);
     523         722 :     panMap = static_cast<int *>(CPLMalloc(nSrcFieldCount * sizeof(int)));
     524        3380 :     for (int i = 0; i < nSrcFieldCount; i++)
     525             :     {
     526        2658 :         const OGRFieldDefn *poSrcFieldDefn = poSrcFeatureDefn->GetFieldDefn(i);
     527        2658 :         if (m_aosIgnoredFields.FindString(poSrcFieldDefn->GetNameRef()) == -1)
     528             :         {
     529             :             const auto oIter =
     530        2647 :                 oMapDstFieldNameToIdx.find(poSrcFieldDefn->GetNameRef());
     531        2647 :             panMap[i] =
     532        2647 :                 oIter == oMapDstFieldNameToIdx.end() ? -1 : oIter->second;
     533             :         }
     534             :         else
     535             :         {
     536          11 :             panMap[i] = -1;
     537             :         }
     538             :     }
     539             : 
     540         722 :     if (m_apoSrcLayers[iCurLayer]->TestCapability(OLCIgnoreFields))
     541             :     {
     542        1364 :         CPLStringList aosFieldSrc;
     543         710 :         for (const char *pszFieldName : cpl::Iterate(m_aosIgnoredFields))
     544             :         {
     545          69 :             if (EQUAL(pszFieldName, "OGR_GEOMETRY") ||
     546          13 :                 EQUAL(pszFieldName, "OGR_STYLE") ||
     547          43 :                 poSrcFeatureDefn->GetFieldIndex(pszFieldName) >= 0 ||
     548           2 :                 poSrcFeatureDefn->GetGeomFieldIndex(pszFieldName) >= 0)
     549             :             {
     550          26 :                 aosFieldSrc.AddString(pszFieldName);
     551             :             }
     552             :         }
     553             : 
     554        1364 :         std::map<std::string, int> oMapSrcFieldNameToIdx;
     555        3314 :         for (int i = 0; i < nSrcFieldCount; i++)
     556             :         {
     557             :             const OGRFieldDefn *poSrcFieldDefn =
     558        2632 :                 poSrcFeatureDefn->GetFieldDefn(i);
     559        2632 :             oMapSrcFieldNameToIdx[poSrcFieldDefn->GetNameRef()] = i;
     560             :         }
     561             : 
     562             :         /* Attribute fields */
     563        1364 :         std::vector<bool> abSrcFieldsUsed(nSrcFieldCount);
     564        2858 :         for (int iField = 0; iField < nDstFieldCount; iField++)
     565             :         {
     566             :             const OGRFieldDefn *poFieldDefn =
     567        2176 :                 poFeatureDefn->GetFieldDefn(iField);
     568             :             const auto oIter =
     569        2176 :                 oMapSrcFieldNameToIdx.find(poFieldDefn->GetNameRef());
     570             :             const int iSrcField =
     571        2176 :                 oIter == oMapSrcFieldNameToIdx.end() ? -1 : oIter->second;
     572        2176 :             if (iSrcField >= 0)
     573        1855 :                 abSrcFieldsUsed[iSrcField] = true;
     574             :         }
     575        3314 :         for (int iSrcField = 0; iSrcField < nSrcFieldCount; iSrcField++)
     576             :         {
     577        2632 :             if (!abSrcFieldsUsed[iSrcField])
     578             :             {
     579             :                 const OGRFieldDefn *poSrcDefn =
     580         777 :                     poSrcFeatureDefn->GetFieldDefn(iSrcField);
     581         777 :                 aosFieldSrc.AddString(poSrcDefn->GetNameRef());
     582             :             }
     583             :         }
     584             : 
     585             :         /* geometry fields now */
     586         682 :         abSrcFieldsUsed.clear();
     587         682 :         abSrcFieldsUsed.resize(poSrcFeatureDefn->GetGeomFieldCount());
     588        1887 :         for (int iField = 0; iField < poFeatureDefn->GetGeomFieldCount();
     589             :              iField++)
     590             :         {
     591             :             const OGRGeomFieldDefn *poFieldDefn =
     592        1205 :                 poFeatureDefn->GetGeomFieldDefn(iField);
     593             :             const int iSrcField =
     594        1205 :                 poSrcFeatureDefn->GetGeomFieldIndex(poFieldDefn->GetNameRef());
     595        1205 :             if (iSrcField >= 0)
     596        1092 :                 abSrcFieldsUsed[iSrcField] = true;
     597             :         }
     598        2155 :         for (int iSrcField = 0;
     599        2155 :              iSrcField < poSrcFeatureDefn->GetGeomFieldCount(); iSrcField++)
     600             :         {
     601        1473 :             if (!abSrcFieldsUsed[iSrcField])
     602             :             {
     603             :                 const OGRGeomFieldDefn *poSrcDefn =
     604         381 :                     poSrcFeatureDefn->GetGeomFieldDefn(iSrcField);
     605         381 :                 aosFieldSrc.AddString(poSrcDefn->GetNameRef());
     606             :             }
     607             :         }
     608             : 
     609         682 :         m_apoSrcLayers[iCurLayer]->SetIgnoredFields(aosFieldSrc.List());
     610             :     }
     611         722 : }
     612             : 
     613             : /************************************************************************/
     614             : /*                             ResetReading()                           */
     615             : /************************************************************************/
     616             : 
     617        1014 : void OGRUnionLayer::ResetReading()
     618             : {
     619        1014 :     iCurLayer = -1;
     620        1014 : }
     621             : 
     622             : /************************************************************************/
     623             : /*                         AutoWarpLayerIfNecessary()                   */
     624             : /************************************************************************/
     625             : 
     626        1123 : void OGRUnionLayer::AutoWarpLayerIfNecessary(int iLayer)
     627             : {
     628        2246 :     std::lock_guard oLock(m_oMutex);
     629             : 
     630        1123 :     if (!m_apoSrcLayers[iLayer].bCheckIfAutoWrap)
     631             :     {
     632         125 :         m_apoSrcLayers[iLayer].bCheckIfAutoWrap = true;
     633             : 
     634         269 :         for (int iField = 0; iField < GetLayerDefn()->GetGeomFieldCount();
     635             :              iField++)
     636             :         {
     637             :             const OGRSpatialReference *poSRS =
     638         144 :                 GetLayerDefn()->GetGeomFieldDefn(iField)->GetSpatialRef();
     639             : 
     640             :             OGRFeatureDefn *poSrcFeatureDefn =
     641         144 :                 m_apoSrcLayers[iLayer]->GetLayerDefn();
     642         144 :             int iSrcGeomField = poSrcFeatureDefn->GetGeomFieldIndex(
     643         144 :                 GetLayerDefn()->GetGeomFieldDefn(iField)->GetNameRef());
     644         144 :             if (iSrcGeomField >= 0)
     645             :             {
     646             :                 const OGRSpatialReference *poSRS2 =
     647         135 :                     poSrcFeatureDefn->GetGeomFieldDefn(iSrcGeomField)
     648         135 :                         ->GetSpatialRef();
     649             : 
     650         135 :                 if ((poSRS == nullptr && poSRS2 != nullptr) ||
     651         101 :                     (poSRS != nullptr && poSRS2 == nullptr))
     652             :                 {
     653           0 :                     CPLError(
     654             :                         CE_Warning, CPLE_AppDefined,
     655             :                         "SRS of geometry field '%s' layer %s not "
     656             :                         "consistent with UnionLayer SRS",
     657           0 :                         GetLayerDefn()->GetGeomFieldDefn(iField)->GetNameRef(),
     658           0 :                         m_apoSrcLayers[iLayer]->GetName());
     659             :                 }
     660         101 :                 else if (poSRS != nullptr && poSRS2 != nullptr &&
     661         236 :                          poSRS != poSRS2 && !poSRS->IsSame(poSRS2))
     662             :                 {
     663           4 :                     CPLDebug(
     664             :                         "VRT",
     665             :                         "SRS of geometry field '%s' layer %s not "
     666             :                         "consistent with UnionLayer SRS. "
     667             :                         "Trying auto warping",
     668           4 :                         GetLayerDefn()->GetGeomFieldDefn(iField)->GetNameRef(),
     669           4 :                         m_apoSrcLayers[iLayer]->GetName());
     670             :                     std::unique_ptr<OGRCoordinateTransformation> poCT(
     671           8 :                         OGRCreateCoordinateTransformation(poSRS2, poSRS));
     672             :                     std::unique_ptr<OGRCoordinateTransformation> poReversedCT(
     673           8 :                         (poCT != nullptr) ? poCT->GetInverse() : nullptr);
     674           4 :                     if (poReversedCT != nullptr)
     675             :                     {
     676           4 :                         auto [poSrcLayer, bOwned] =
     677           4 :                             m_apoSrcLayers[iLayer].release();
     678           8 :                         m_apoSrcLayers[iLayer].reset(
     679           4 :                             std::make_unique<OGRWarpedLayer>(
     680             :                                 poSrcLayer, iSrcGeomField, bOwned,
     681           8 :                                 poCT.release(), poReversedCT.release()));
     682             :                     }
     683             :                     else
     684             :                     {
     685           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     686             :                                  "AutoWarpLayerIfNecessary failed to create "
     687             :                                  "poCT or poReversedCT.");
     688             :                     }
     689             :                 }
     690             :             }
     691             :         }
     692             :     }
     693        1123 : }
     694             : 
     695             : /************************************************************************/
     696             : /*                           GetNextFeature()                           */
     697             : /************************************************************************/
     698             : 
     699        2857 : OGRFeature *OGRUnionLayer::GetNextFeature()
     700             : {
     701        2857 :     if (poFeatureDefn == nullptr)
     702           4 :         GetLayerDefn();
     703             : 
     704        2857 :     if (iCurLayer < 0)
     705             :     {
     706         437 :         iCurLayer = 0;
     707         437 :         ConfigureActiveLayer();
     708         437 :         nNextFID = 0;
     709             :     }
     710        2420 :     else if (iCurLayer == static_cast<int>(m_apoSrcLayers.size()))
     711          27 :         return nullptr;
     712             : 
     713        2830 :     m_bHasAlreadyIteratedOverFeatures = true;
     714             : 
     715             :     while (true)
     716             :     {
     717             :         auto poSrcFeature = std::unique_ptr<OGRFeature>(
     718        3579 :             m_apoSrcLayers[iCurLayer]->GetNextFeature());
     719        3579 :         if (poSrcFeature == nullptr)
     720             :         {
     721         527 :             iCurLayer++;
     722         527 :             if (iCurLayer < static_cast<int>(m_apoSrcLayers.size()))
     723             :             {
     724         246 :                 ConfigureActiveLayer();
     725         246 :                 continue;
     726             :             }
     727             :             else
     728             :             {
     729         281 :                 if (!m_fidRangesInvalid && !bPreserveSrcFID)
     730             :                 {
     731          47 :                     m_fidRangesComplete = true;
     732             :                 }
     733         281 :                 break;
     734             :             }
     735             :         }
     736             : 
     737        3052 :         auto poFeature = TranslateFromSrcLayer(poSrcFeature.get(), -1);
     738             : 
     739             :         // When iterating over all features, build a ma
     740        3052 :         if (!m_fidRangesInvalid && !bPreserveSrcFID && !m_fidRangesComplete)
     741             :         {
     742         432 :             if (m_fidRanges.empty() ||
     743         782 :                 m_fidRanges.back().nLayerIdx != iCurLayer ||
     744         350 :                 poSrcFeature->GetFID() > m_fidRanges.back().nSrcFIDStart +
     745         350 :                                              m_fidRanges.back().nFIDCount)
     746             :             {
     747          82 :                 FIDRange range;
     748          82 :                 range.nDstFIDStart = poFeature->GetFID();
     749          82 :                 range.nFIDCount = 1;
     750          82 :                 range.nSrcFIDStart = poSrcFeature->GetFID();
     751          82 :                 range.nLayerIdx = iCurLayer;
     752          82 :                 m_fidRanges.push_back(std::move(range));
     753          82 :                 if (m_fidRanges.size() > 1000 * 1000)
     754             :                 {
     755           0 :                     m_fidRangesInvalid = true;
     756           0 :                     m_fidRanges.clear();
     757             :                 }
     758             :             }
     759         350 :             else if (poSrcFeature->GetFID() == m_fidRanges.back().nSrcFIDStart +
     760         350 :                                                    m_fidRanges.back().nFIDCount)
     761             :             {
     762         350 :                 ++m_fidRanges.back().nFIDCount;
     763             :             }
     764             :             else
     765             :             {
     766             :                 // Decreasing src FID
     767           0 :                 m_fidRangesInvalid = true;
     768           0 :                 m_fidRanges.clear();
     769             :             }
     770             :         }
     771             : 
     772        6420 :         if ((m_poFilterGeom == nullptr ||
     773        6104 :              FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
     774        3052 :             (m_poAttrQuery == nullptr ||
     775         875 :              m_poAttrQuery->Evaluate(poFeature.get())))
     776             :         {
     777        2549 :             return poFeature.release();
     778             :         }
     779         749 :     }
     780         281 :     return nullptr;
     781             : }
     782             : 
     783             : /************************************************************************/
     784             : /*                             GetFeature()                             */
     785             : /************************************************************************/
     786             : 
     787          95 : OGRFeature *OGRUnionLayer::GetFeature(GIntBig nFeatureId)
     788             : {
     789          95 :     std::unique_ptr<OGRFeature> poFeature;
     790             : 
     791          95 :     if (!bPreserveSrcFID)
     792             :     {
     793          95 :         if (m_fidRangesComplete)
     794             :         {
     795          39 :             if (!m_fidRanges.empty() &&
     796          78 :                 nFeatureId >= m_fidRanges[0].nDstFIDStart &&
     797          39 :                 nFeatureId < m_fidRanges.back().nDstFIDStart +
     798          39 :                                  m_fidRanges.back().nFIDCount)
     799             :             {
     800             :                 // Dichotomic search
     801          39 :                 size_t iStart = 0;
     802          39 :                 size_t iEnd = m_fidRanges.size() - 1;
     803         117 :                 while (iEnd - iStart > 1)
     804             :                 {
     805          78 :                     size_t iMiddle = (iStart + iEnd) / 2;
     806          78 :                     if (nFeatureId < m_fidRanges[iMiddle].nDstFIDStart)
     807             :                     {
     808          35 :                         iEnd = iMiddle;
     809             :                     }
     810             :                     else
     811             :                     {
     812          43 :                         iStart = iMiddle;
     813             :                     }
     814             :                 }
     815             : 
     816          39 :                 size_t iRange = iStart;
     817          39 :                 CPLAssert(nFeatureId >= m_fidRanges[iStart].nDstFIDStart);
     818          39 :                 CPLAssert(nFeatureId < m_fidRanges[iEnd].nDstFIDStart +
     819             :                                            m_fidRanges[iEnd].nFIDCount);
     820          78 :                 if (iStart < iEnd &&
     821          39 :                     nFeatureId >= m_fidRanges[iEnd].nDstFIDStart)
     822           6 :                     ++iRange;
     823          39 :                 if (nFeatureId < m_fidRanges[iRange].nDstFIDStart +
     824          39 :                                      m_fidRanges[iRange].nFIDCount)
     825             :                 {
     826          39 :                     iCurLayer = m_fidRanges[iRange].nLayerIdx;
     827          39 :                     ConfigureActiveLayer();
     828             : 
     829          39 :                     const auto nSrcFID = nFeatureId -
     830          39 :                                          m_fidRanges[iRange].nDstFIDStart +
     831          39 :                                          m_fidRanges[iRange].nSrcFIDStart;
     832             : 
     833             :                     auto poSrcFeature = std::unique_ptr<OGRFeature>(
     834          78 :                         m_apoSrcLayers[iCurLayer]->GetFeature(nSrcFID));
     835             :                     // In theory below assertion should be true, unless the
     836             :                     // dataset has been modified behind our back.
     837             :                     // CPLAssert(poSrcFeature);
     838          39 :                     if (poSrcFeature)
     839             :                     {
     840          78 :                         poFeature = TranslateFromSrcLayer(poSrcFeature.get(),
     841          39 :                                                           nFeatureId);
     842             :                     }
     843             :                 }
     844             :             }
     845             :         }
     846             :         else
     847             :         {
     848          56 :             poFeature.reset(OGRLayer::GetFeature(nFeatureId));
     849             :         }
     850             :     }
     851             :     else
     852             :     {
     853           0 :         const int iGeomFieldFilterSave = m_iGeomFieldFilter;
     854           0 :         std::unique_ptr<OGRGeometry> poGeomSave(m_poFilterGeom);
     855           0 :         m_poFilterGeom = nullptr;
     856           0 :         SetSpatialFilter(nullptr);
     857             : 
     858           0 :         for (int i = 0; i < static_cast<int>(m_apoSrcLayers.size()); i++)
     859             :         {
     860           0 :             iCurLayer = i;
     861           0 :             ConfigureActiveLayer();
     862             : 
     863             :             auto poSrcFeature = std::unique_ptr<OGRFeature>(
     864           0 :                 m_apoSrcLayers[i]->GetFeature(nFeatureId));
     865           0 :             if (poSrcFeature != nullptr)
     866             :             {
     867             :                 poFeature =
     868           0 :                     TranslateFromSrcLayer(poSrcFeature.get(), nFeatureId);
     869           0 :                 break;
     870             :             }
     871             :         }
     872             : 
     873           0 :         SetSpatialFilter(iGeomFieldFilterSave, poGeomSave.get());
     874             : 
     875           0 :         ResetReading();
     876             :     }
     877             : 
     878         190 :     return poFeature.release();
     879             : }
     880             : 
     881             : /************************************************************************/
     882             : /*                          ICreateFeature()                             */
     883             : /************************************************************************/
     884             : 
     885           5 : OGRErr OGRUnionLayer::ICreateFeature(OGRFeature *poFeature)
     886             : {
     887           5 :     if (osSourceLayerFieldName.empty())
     888             :     {
     889           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     890             :                  "CreateFeature() not supported when SourceLayerFieldName is "
     891             :                  "not set");
     892           1 :         return OGRERR_FAILURE;
     893             :     }
     894             : 
     895           4 :     if (poFeature->GetFID() != OGRNullFID)
     896             :     {
     897           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     898             :                  "CreateFeature() not supported when FID is set");
     899           1 :         return OGRERR_FAILURE;
     900             :     }
     901             : 
     902           3 :     if (!poFeature->IsFieldSetAndNotNull(0))
     903             :     {
     904           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     905             :                  "CreateFeature() not supported when '%s' field is not set",
     906             :                  osSourceLayerFieldName.c_str());
     907           1 :         return OGRERR_FAILURE;
     908             :     }
     909             : 
     910           2 :     m_fidRangesComplete = false;
     911           2 :     m_fidRanges.clear();
     912             : 
     913           2 :     const char *pszSrcLayerName = poFeature->GetFieldAsString(0);
     914           5 :     for (auto &oLayer : m_apoSrcLayers)
     915             :     {
     916           4 :         if (strcmp(pszSrcLayerName, oLayer->GetName()) == 0)
     917             :         {
     918           1 :             oLayer.bModified = true;
     919             : 
     920           1 :             OGRFeature *poSrcFeature = new OGRFeature(oLayer->GetLayerDefn());
     921           1 :             poSrcFeature->SetFrom(poFeature, TRUE);
     922           1 :             OGRErr eErr = oLayer->CreateFeature(poSrcFeature);
     923           1 :             if (eErr == OGRERR_NONE)
     924           1 :                 poFeature->SetFID(poSrcFeature->GetFID());
     925           1 :             delete poSrcFeature;
     926           1 :             return eErr;
     927             :         }
     928             :     }
     929             : 
     930           1 :     CPLError(CE_Failure, CPLE_NotSupported,
     931             :              "CreateFeature() not supported : '%s' source layer does not exist",
     932             :              pszSrcLayerName);
     933           1 :     return OGRERR_FAILURE;
     934             : }
     935             : 
     936             : /************************************************************************/
     937             : /*                             ISetFeature()                             */
     938             : /************************************************************************/
     939             : 
     940          14 : OGRErr OGRUnionLayer::ISetFeature(OGRFeature *poFeature)
     941             : {
     942          14 :     if (!bPreserveSrcFID)
     943             :     {
     944          10 :         CPLError(CE_Failure, CPLE_NotSupported,
     945             :                  "SetFeature() not supported when PreserveSrcFID is OFF");
     946          10 :         return OGRERR_FAILURE;
     947             :     }
     948             : 
     949           4 :     if (osSourceLayerFieldName.empty())
     950             :     {
     951           0 :         CPLError(
     952             :             CE_Failure, CPLE_NotSupported,
     953             :             "SetFeature() not supported when SourceLayerFieldName is not set");
     954           0 :         return OGRERR_FAILURE;
     955             :     }
     956             : 
     957           4 :     if (poFeature->GetFID() == OGRNullFID)
     958             :     {
     959           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     960             :                  "SetFeature() not supported when FID is not set");
     961           1 :         return OGRERR_FAILURE;
     962             :     }
     963             : 
     964           3 :     if (!poFeature->IsFieldSetAndNotNull(0))
     965             :     {
     966           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     967             :                  "SetFeature() not supported when '%s' field is not set",
     968             :                  osSourceLayerFieldName.c_str());
     969           1 :         return OGRERR_FAILURE;
     970             :     }
     971             : 
     972           2 :     const char *pszSrcLayerName = poFeature->GetFieldAsString(0);
     973           5 :     for (auto &oLayer : m_apoSrcLayers)
     974             :     {
     975           4 :         if (strcmp(pszSrcLayerName, oLayer->GetName()) == 0)
     976             :         {
     977           1 :             oLayer.bModified = true;
     978             : 
     979           1 :             OGRFeature *poSrcFeature = new OGRFeature(oLayer->GetLayerDefn());
     980           1 :             poSrcFeature->SetFrom(poFeature, TRUE);
     981           1 :             poSrcFeature->SetFID(poFeature->GetFID());
     982           1 :             OGRErr eErr = oLayer->SetFeature(poSrcFeature);
     983           1 :             delete poSrcFeature;
     984           1 :             return eErr;
     985             :         }
     986             :     }
     987             : 
     988           1 :     CPLError(CE_Failure, CPLE_NotSupported,
     989             :              "SetFeature() not supported : '%s' source layer does not exist",
     990             :              pszSrcLayerName);
     991           1 :     return OGRERR_FAILURE;
     992             : }
     993             : 
     994             : /************************************************************************/
     995             : /*                          IUpsertFeature()                            */
     996             : /************************************************************************/
     997             : 
     998           0 : OGRErr OGRUnionLayer::IUpsertFeature(OGRFeature *poFeature)
     999             : {
    1000           0 :     if (std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID())))
    1001             :     {
    1002           0 :         return ISetFeature(poFeature);
    1003             :     }
    1004             :     else
    1005             :     {
    1006           0 :         return ICreateFeature(poFeature);
    1007             :     }
    1008             : }
    1009             : 
    1010             : /************************************************************************/
    1011             : /*                           IUpdateFeature()                           */
    1012             : /************************************************************************/
    1013             : 
    1014           0 : OGRErr OGRUnionLayer::IUpdateFeature(OGRFeature *poFeature,
    1015             :                                      int nUpdatedFieldsCount,
    1016             :                                      const int *panUpdatedFieldsIdx,
    1017             :                                      int nUpdatedGeomFieldsCount,
    1018             :                                      const int *panUpdatedGeomFieldsIdx,
    1019             :                                      bool bUpdateStyleString)
    1020             : {
    1021           0 :     if (!bPreserveSrcFID)
    1022             :     {
    1023           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1024             :                  "UpdateFeature() not supported when PreserveSrcFID is OFF");
    1025           0 :         return OGRERR_FAILURE;
    1026             :     }
    1027             : 
    1028           0 :     if (osSourceLayerFieldName.empty())
    1029             :     {
    1030           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1031             :                  "UpdateFeature() not supported when SourceLayerFieldName is "
    1032             :                  "not set");
    1033           0 :         return OGRERR_FAILURE;
    1034             :     }
    1035             : 
    1036           0 :     if (poFeature->GetFID() == OGRNullFID)
    1037             :     {
    1038           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1039             :                  "UpdateFeature() not supported when FID is not set");
    1040           0 :         return OGRERR_FAILURE;
    1041             :     }
    1042             : 
    1043           0 :     if (!poFeature->IsFieldSetAndNotNull(0))
    1044             :     {
    1045           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1046             :                  "UpdateFeature() not supported when '%s' field is not set",
    1047             :                  osSourceLayerFieldName.c_str());
    1048           0 :         return OGRERR_FAILURE;
    1049             :     }
    1050             : 
    1051           0 :     const char *pszSrcLayerName = poFeature->GetFieldAsString(0);
    1052           0 :     for (int i = 0; i < static_cast<int>(m_apoSrcLayers.size()); i++)
    1053             :     {
    1054           0 :         if (strcmp(pszSrcLayerName, m_apoSrcLayers[i]->GetName()) == 0)
    1055             :         {
    1056           0 :             m_apoSrcLayers[i].bModified = true;
    1057             : 
    1058           0 :             const auto poSrcLayerDefn = m_apoSrcLayers[i]->GetLayerDefn();
    1059           0 :             OGRFeature *poSrcFeature = new OGRFeature(poSrcLayerDefn);
    1060           0 :             poSrcFeature->SetFrom(poFeature, TRUE);
    1061           0 :             poSrcFeature->SetFID(poFeature->GetFID());
    1062             : 
    1063             :             // We could potentially have a pre-computed map from indices in
    1064             :             // poLayerDefn to indices in poSrcLayerDefn
    1065           0 :             std::vector<int> anSrcUpdatedFieldIdx;
    1066           0 :             const auto poLayerDefn = GetLayerDefn();
    1067           0 :             for (int j = 0; j < nUpdatedFieldsCount; ++j)
    1068             :             {
    1069           0 :                 if (panUpdatedFieldsIdx[j] != 0)
    1070             :                 {
    1071           0 :                     const int nNewIdx = poSrcLayerDefn->GetFieldIndex(
    1072           0 :                         poLayerDefn->GetFieldDefn(panUpdatedFieldsIdx[j])
    1073           0 :                             ->GetNameRef());
    1074           0 :                     if (nNewIdx >= 0)
    1075             :                     {
    1076           0 :                         anSrcUpdatedFieldIdx.push_back(nNewIdx);
    1077             :                     }
    1078             :                 }
    1079             :             }
    1080           0 :             std::vector<int> anSrcUpdatedGeomFieldIdx;
    1081           0 :             for (int j = 0; j < nUpdatedGeomFieldsCount; ++j)
    1082             :             {
    1083           0 :                 if (panUpdatedGeomFieldsIdx[j] != 0)
    1084             :                 {
    1085           0 :                     const int nNewIdx = poSrcLayerDefn->GetGeomFieldIndex(
    1086             :                         poLayerDefn
    1087           0 :                             ->GetGeomFieldDefn(panUpdatedGeomFieldsIdx[j])
    1088           0 :                             ->GetNameRef());
    1089           0 :                     if (nNewIdx >= 0)
    1090             :                     {
    1091           0 :                         anSrcUpdatedGeomFieldIdx.push_back(nNewIdx);
    1092             :                     }
    1093             :                 }
    1094             :             }
    1095             : 
    1096           0 :             OGRErr eErr = m_apoSrcLayers[i]->UpdateFeature(
    1097           0 :                 poSrcFeature, static_cast<int>(anSrcUpdatedFieldIdx.size()),
    1098           0 :                 anSrcUpdatedFieldIdx.data(),
    1099           0 :                 static_cast<int>(anSrcUpdatedGeomFieldIdx.size()),
    1100           0 :                 anSrcUpdatedGeomFieldIdx.data(), bUpdateStyleString);
    1101           0 :             delete poSrcFeature;
    1102           0 :             return eErr;
    1103             :         }
    1104             :     }
    1105             : 
    1106           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1107             :              "UpdateFeature() not supported : '%s' source layer does not exist",
    1108             :              pszSrcLayerName);
    1109           0 :     return OGRERR_FAILURE;
    1110             : }
    1111             : 
    1112             : /************************************************************************/
    1113             : /*                           GetSpatialRef()                            */
    1114             : /************************************************************************/
    1115             : 
    1116         223 : const OGRSpatialReference *OGRUnionLayer::GetSpatialRef() const
    1117             : {
    1118         223 :     if (nGeomFields < 0)
    1119           0 :         return nullptr;
    1120         223 :     if (nGeomFields >= 1 && papoGeomFields[0]->bSRSSet)
    1121           1 :         return papoGeomFields[0]->GetSpatialRef();
    1122             : 
    1123         222 :     if (poGlobalSRS == nullptr)
    1124             :     {
    1125         151 :         poGlobalSRS = m_apoSrcLayers[0]->GetSpatialRef();
    1126         151 :         if (poGlobalSRS != nullptr)
    1127          32 :             const_cast<OGRSpatialReference *>(poGlobalSRS)->Reference();
    1128             :     }
    1129         222 :     return poGlobalSRS;
    1130             : }
    1131             : 
    1132             : /************************************************************************/
    1133             : /*                      GetAttrFilterPassThroughValue()                 */
    1134             : /************************************************************************/
    1135             : 
    1136        1190 : int OGRUnionLayer::GetAttrFilterPassThroughValue() const
    1137             : {
    1138        1190 :     if (m_poAttrQuery == nullptr)
    1139         936 :         return TRUE;
    1140             : 
    1141         254 :     if (bAttrFilterPassThroughValue >= 0)
    1142         154 :         return bAttrFilterPassThroughValue;
    1143             : 
    1144         100 :     char **papszUsedFields = m_poAttrQuery->GetUsedFields();
    1145         100 :     int bRet = TRUE;
    1146             : 
    1147         289 :     for (auto &oLayer : m_apoSrcLayers)
    1148             :     {
    1149         189 :         const OGRFeatureDefn *poSrcFeatureDefn = oLayer->GetLayerDefn();
    1150         189 :         char **papszIter = papszUsedFields;
    1151         255 :         while (papszIter != nullptr && *papszIter != nullptr)
    1152             :         {
    1153          79 :             int bIsSpecial = FALSE;
    1154         458 :             for (int i = 0; i < SPECIAL_FIELD_COUNT; i++)
    1155             :             {
    1156         383 :                 if (EQUAL(*papszIter, SpecialFieldNames[i]))
    1157             :                 {
    1158           4 :                     bIsSpecial = TRUE;
    1159           4 :                     break;
    1160             :                 }
    1161             :             }
    1162          79 :             if (!bIsSpecial && poSrcFeatureDefn->GetFieldIndex(*papszIter) < 0)
    1163             :             {
    1164          13 :                 bRet = FALSE;
    1165          13 :                 break;
    1166             :             }
    1167          66 :             papszIter++;
    1168             :         }
    1169             :     }
    1170             : 
    1171         100 :     CSLDestroy(papszUsedFields);
    1172             : 
    1173         100 :     bAttrFilterPassThroughValue = bRet;
    1174             : 
    1175         100 :     return bRet;
    1176             : }
    1177             : 
    1178             : /************************************************************************/
    1179             : /*                  ApplyAttributeFilterToSrcLayer()                    */
    1180             : /************************************************************************/
    1181             : 
    1182        1028 : void OGRUnionLayer::ApplyAttributeFilterToSrcLayer(int iSubLayer)
    1183             : {
    1184        2056 :     std::lock_guard oLock(m_oMutex);
    1185             : 
    1186        1028 :     CPLAssert(iSubLayer >= 0 &&
    1187             :               iSubLayer < static_cast<int>(m_apoSrcLayers.size()));
    1188             : 
    1189        1028 :     if (GetAttrFilterPassThroughValue())
    1190         998 :         m_apoSrcLayers[iSubLayer]->SetAttributeFilter(pszAttributeFilter);
    1191             :     else
    1192          30 :         m_apoSrcLayers[iSubLayer]->SetAttributeFilter(nullptr);
    1193        1028 : }
    1194             : 
    1195             : /************************************************************************/
    1196             : /*                          GetFeatureCount()                           */
    1197             : /************************************************************************/
    1198             : 
    1199         157 : GIntBig OGRUnionLayer::GetFeatureCount(int bForce)
    1200             : {
    1201         157 :     if (nFeatureCount >= 0 && m_poFilterGeom == nullptr &&
    1202           1 :         m_poAttrQuery == nullptr)
    1203             :     {
    1204           1 :         return nFeatureCount;
    1205             :     }
    1206             : 
    1207         156 :     if (!GetAttrFilterPassThroughValue())
    1208           5 :         return OGRLayer::GetFeatureCount(bForce);
    1209             : 
    1210         151 :     GIntBig nRet = 0;
    1211         442 :     for (int i = 0; i < static_cast<int>(m_apoSrcLayers.size()); i++)
    1212             :     {
    1213         292 :         AutoWarpLayerIfNecessary(i);
    1214         292 :         ApplyAttributeFilterToSrcLayer(i);
    1215         292 :         SetSpatialFilterToSourceLayer(m_apoSrcLayers[i].poLayer);
    1216         292 :         const GIntBig nThisLayerFC = m_apoSrcLayers[i]->GetFeatureCount(bForce);
    1217         584 :         if (nThisLayerFC < 0 ||
    1218         292 :             nThisLayerFC > std::numeric_limits<GIntBig>::max() - nRet)
    1219           1 :             return 0;
    1220         291 :         nRet += nThisLayerFC;
    1221             :     }
    1222         150 :     ResetReading();
    1223         150 :     return nRet;
    1224             : }
    1225             : 
    1226             : /************************************************************************/
    1227             : /*                         SetAttributeFilter()                         */
    1228             : /************************************************************************/
    1229             : 
    1230         437 : OGRErr OGRUnionLayer::SetAttributeFilter(const char *pszAttributeFilterIn)
    1231             : {
    1232         437 :     if (pszAttributeFilterIn == nullptr && pszAttributeFilter == nullptr)
    1233         201 :         return OGRERR_NONE;
    1234         236 :     if (pszAttributeFilterIn != nullptr && pszAttributeFilter != nullptr &&
    1235          61 :         strcmp(pszAttributeFilterIn, pszAttributeFilter) == 0)
    1236           8 :         return OGRERR_NONE;
    1237             : 
    1238         228 :     if (m_bHasAlreadyIteratedOverFeatures)
    1239             :     {
    1240         226 :         m_fidRanges.clear();
    1241         226 :         m_fidRangesComplete = false;
    1242         226 :         m_fidRangesInvalid = true;
    1243             :     }
    1244             : 
    1245         228 :     if (poFeatureDefn == nullptr)
    1246           1 :         GetLayerDefn();
    1247             : 
    1248         228 :     bAttrFilterPassThroughValue = -1;
    1249             : 
    1250         228 :     OGRErr eErr = OGRLayer::SetAttributeFilter(pszAttributeFilterIn);
    1251         228 :     if (eErr != OGRERR_NONE)
    1252           0 :         return eErr;
    1253             : 
    1254         228 :     CPLFree(pszAttributeFilter);
    1255         228 :     pszAttributeFilter =
    1256         228 :         pszAttributeFilterIn ? CPLStrdup(pszAttributeFilterIn) : nullptr;
    1257             : 
    1258         228 :     if (iCurLayer >= 0 && iCurLayer < static_cast<int>(m_apoSrcLayers.size()))
    1259           0 :         ApplyAttributeFilterToSrcLayer(iCurLayer);
    1260             : 
    1261         228 :     return OGRERR_NONE;
    1262             : }
    1263             : 
    1264             : /************************************************************************/
    1265             : /*                           TestCapability()                           */
    1266             : /************************************************************************/
    1267             : 
    1268         390 : int OGRUnionLayer::TestCapability(const char *pszCap) const
    1269             : {
    1270         390 :     if (EQUAL(pszCap, OLCFastFeatureCount))
    1271             :     {
    1272           7 :         if (nFeatureCount >= 0 && m_poFilterGeom == nullptr &&
    1273           3 :             m_poAttrQuery == nullptr)
    1274           1 :             return TRUE;
    1275             : 
    1276           6 :         if (!GetAttrFilterPassThroughValue())
    1277           1 :             return FALSE;
    1278             : 
    1279          15 :         for (int i = 0; i < static_cast<int>(m_apoSrcLayers.size()); i++)
    1280             :         {
    1281          10 :             const_cast<OGRUnionLayer *>(this)->AutoWarpLayerIfNecessary(i);
    1282          10 :             const_cast<OGRUnionLayer *>(this)->ApplyAttributeFilterToSrcLayer(
    1283             :                 i);
    1284          10 :             const_cast<OGRUnionLayer *>(this)->SetSpatialFilterToSourceLayer(
    1285          10 :                 m_apoSrcLayers[i].poLayer);
    1286          10 :             if (!m_apoSrcLayers[i]->TestCapability(pszCap))
    1287           0 :                 return FALSE;
    1288             :         }
    1289           5 :         return TRUE;
    1290             :     }
    1291             : 
    1292         383 :     if (EQUAL(pszCap, OLCFastGetExtent))
    1293             :     {
    1294          21 :         if (nGeomFields >= 1 && papoGeomFields[0]->sStaticEnvelope.IsInit())
    1295           1 :             return TRUE;
    1296             : 
    1297          32 :         for (int i = 0; i < static_cast<int>(m_apoSrcLayers.size()); i++)
    1298             :         {
    1299          25 :             const_cast<OGRUnionLayer *>(this)->AutoWarpLayerIfNecessary(i);
    1300          25 :             if (!m_apoSrcLayers[i]->TestCapability(pszCap))
    1301          13 :                 return FALSE;
    1302             :         }
    1303           7 :         return TRUE;
    1304             :     }
    1305             : 
    1306         362 :     if (EQUAL(pszCap, OLCFastSpatialFilter))
    1307             :     {
    1308           6 :         for (int i = 0; i < static_cast<int>(m_apoSrcLayers.size()); i++)
    1309             :         {
    1310           4 :             const_cast<OGRUnionLayer *>(this)->AutoWarpLayerIfNecessary(i);
    1311           4 :             const_cast<OGRUnionLayer *>(this)->ApplyAttributeFilterToSrcLayer(
    1312             :                 i);
    1313           4 :             if (!m_apoSrcLayers[i]->TestCapability(pszCap))
    1314           0 :                 return FALSE;
    1315             :         }
    1316           2 :         return TRUE;
    1317             :     }
    1318             : 
    1319         360 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
    1320             :     {
    1321         178 :         for (auto &oLayer : m_apoSrcLayers)
    1322             :         {
    1323         147 :             if (!oLayer->TestCapability(pszCap))
    1324          82 :                 return FALSE;
    1325             :         }
    1326          31 :         return TRUE;
    1327             :     }
    1328             : 
    1329         247 :     if (EQUAL(pszCap, OLCRandomRead))
    1330             :     {
    1331           3 :         if (!bPreserveSrcFID && !m_fidRangesComplete)
    1332           2 :             return FALSE;
    1333             : 
    1334           6 :         for (auto &oLayer : m_apoSrcLayers)
    1335             :         {
    1336           5 :             if (!oLayer->TestCapability(pszCap))
    1337           0 :                 return FALSE;
    1338             :         }
    1339           1 :         return TRUE;
    1340             :     }
    1341             : 
    1342         244 :     if (EQUAL(pszCap, OLCRandomWrite))
    1343             :     {
    1344          11 :         if (!bPreserveSrcFID || osSourceLayerFieldName.empty())
    1345          10 :             return FALSE;
    1346             : 
    1347           3 :         for (auto &oLayer : m_apoSrcLayers)
    1348             :         {
    1349           2 :             if (!oLayer->TestCapability(pszCap))
    1350           0 :                 return FALSE;
    1351             :         }
    1352           1 :         return TRUE;
    1353             :     }
    1354             : 
    1355         233 :     if (EQUAL(pszCap, OLCSequentialWrite))
    1356             :     {
    1357          11 :         if (osSourceLayerFieldName.empty())
    1358          10 :             return FALSE;
    1359             : 
    1360           3 :         for (auto &oLayer : m_apoSrcLayers)
    1361             :         {
    1362           2 :             if (!oLayer->TestCapability(pszCap))
    1363           0 :                 return FALSE;
    1364             :         }
    1365           1 :         return TRUE;
    1366             :     }
    1367             : 
    1368         222 :     if (EQUAL(pszCap, OLCIgnoreFields))
    1369          12 :         return TRUE;
    1370             : 
    1371         210 :     if (EQUAL(pszCap, OLCCurveGeometries))
    1372          38 :         return TRUE;
    1373             : 
    1374         172 :     return FALSE;
    1375             : }
    1376             : 
    1377             : /************************************************************************/
    1378             : /*                             IGetExtent()                             */
    1379             : /************************************************************************/
    1380             : 
    1381          41 : OGRErr OGRUnionLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
    1382             :                                  bool bForce)
    1383             : {
    1384          51 :     if (iGeomField >= 0 && iGeomField < nGeomFields &&
    1385          10 :         papoGeomFields[iGeomField]->sStaticEnvelope.IsInit())
    1386             :     {
    1387           4 :         *psExtent = papoGeomFields[iGeomField]->sStaticEnvelope;
    1388           4 :         return OGRERR_NONE;
    1389             :     }
    1390             : 
    1391          37 :     if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount())
    1392             :     {
    1393           0 :         if (iGeomField != 0)
    1394             :         {
    1395           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1396             :                      "Invalid geometry field index : %d", iGeomField);
    1397             :         }
    1398           0 :         return OGRERR_FAILURE;
    1399             :     }
    1400             : 
    1401          37 :     int bInit = FALSE;
    1402         107 :     for (int i = 0; i < static_cast<int>(m_apoSrcLayers.size()); i++)
    1403             :     {
    1404          70 :         AutoWarpLayerIfNecessary(i);
    1405             :         int iSrcGeomField =
    1406         140 :             m_apoSrcLayers[i]->GetLayerDefn()->GetGeomFieldIndex(
    1407          70 :                 GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetNameRef());
    1408          70 :         if (iSrcGeomField >= 0)
    1409             :         {
    1410          64 :             if (!bInit)
    1411             :             {
    1412          37 :                 if (m_apoSrcLayers[i]->GetExtent(iSrcGeomField, psExtent,
    1413          37 :                                                  bForce) == OGRERR_NONE)
    1414          33 :                     bInit = TRUE;
    1415             :             }
    1416             :             else
    1417             :             {
    1418          27 :                 OGREnvelope sExtent;
    1419          27 :                 if (m_apoSrcLayers[i]->GetExtent(iSrcGeomField, &sExtent,
    1420          27 :                                                  bForce) == OGRERR_NONE)
    1421             :                 {
    1422          27 :                     psExtent->Merge(sExtent);
    1423             :                 }
    1424             :             }
    1425             :         }
    1426             :     }
    1427          37 :     return (bInit) ? OGRERR_NONE : OGRERR_FAILURE;
    1428             : }
    1429             : 
    1430             : /************************************************************************/
    1431             : /*                        ISetSpatialFilter()                           */
    1432             : /************************************************************************/
    1433             : 
    1434         377 : OGRErr OGRUnionLayer::ISetSpatialFilter(int iGeomField,
    1435             :                                         const OGRGeometry *poGeom)
    1436             : {
    1437         734 :     if (!(m_iGeomFieldFilter == iGeomField &&
    1438         357 :           ((poGeom == nullptr && m_poFilterGeom == nullptr) ||
    1439          79 :            (poGeom && m_poFilterGeom && poGeom->Equals(m_poFilterGeom)))))
    1440             :     {
    1441         121 :         if (m_bHasAlreadyIteratedOverFeatures)
    1442             :         {
    1443         119 :             m_fidRanges.clear();
    1444         119 :             m_fidRangesComplete = false;
    1445         119 :             m_fidRangesInvalid = true;
    1446             :         }
    1447             : 
    1448         121 :         m_iGeomFieldFilter = iGeomField;
    1449         121 :         if (InstallFilter(poGeom))
    1450         121 :             ResetReading();
    1451             : 
    1452         121 :         if (iCurLayer >= 0 &&
    1453           0 :             iCurLayer < static_cast<int>(m_apoSrcLayers.size()))
    1454             :         {
    1455           0 :             SetSpatialFilterToSourceLayer(m_apoSrcLayers[iCurLayer].poLayer);
    1456             :         }
    1457             :     }
    1458             : 
    1459         377 :     return OGRERR_NONE;
    1460             : }
    1461             : 
    1462             : /************************************************************************/
    1463             : /*                        TranslateFromSrcLayer()                       */
    1464             : /************************************************************************/
    1465             : 
    1466             : std::unique_ptr<OGRFeature>
    1467        3091 : OGRUnionLayer::TranslateFromSrcLayer(OGRFeature *poSrcFeature, GIntBig nFID)
    1468             : {
    1469        3091 :     CPLAssert(poSrcFeature->GetFieldCount() == 0 || panMap != nullptr);
    1470        3091 :     CPLAssert(iCurLayer >= 0 &&
    1471             :               iCurLayer < static_cast<int>(m_apoSrcLayers.size()));
    1472             : 
    1473        3091 :     auto poFeature = std::make_unique<OGRFeature>(poFeatureDefn);
    1474        3091 :     poFeature->SetFrom(poSrcFeature, panMap, TRUE);
    1475             : 
    1476        3201 :     if (!osSourceLayerFieldName.empty() &&
    1477         110 :         !poFeatureDefn->GetFieldDefn(0)->IsIgnored())
    1478             :     {
    1479         110 :         poFeature->SetField(0, m_apoSrcLayers[iCurLayer]->GetName());
    1480             :     }
    1481             : 
    1482        6542 :     for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
    1483             :     {
    1484        3451 :         if (poFeatureDefn->GetGeomFieldDefn(i)->IsIgnored())
    1485         120 :             poFeature->SetGeomFieldDirectly(i, nullptr);
    1486             :         else
    1487             :         {
    1488        3331 :             OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
    1489        3331 :             if (poGeom != nullptr)
    1490             :             {
    1491        3134 :                 poGeom->assignSpatialReference(
    1492        3134 :                     poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef());
    1493             :             }
    1494             :         }
    1495             :     }
    1496             : 
    1497        3091 :     if (nFID >= 0)
    1498          39 :         poFeature->SetFID(nFID);
    1499        3052 :     else if (bPreserveSrcFID)
    1500         102 :         poFeature->SetFID(poSrcFeature->GetFID());
    1501             :     else
    1502        2950 :         poFeature->SetFID(nNextFID++);
    1503        3091 :     return poFeature;
    1504             : }
    1505             : 
    1506             : /************************************************************************/
    1507             : /*                          SetIgnoredFields()                          */
    1508             : /************************************************************************/
    1509             : 
    1510         142 : OGRErr OGRUnionLayer::SetIgnoredFields(CSLConstList papszFields)
    1511             : {
    1512         142 :     OGRErr eErr = OGRLayer::SetIgnoredFields(papszFields);
    1513         142 :     if (eErr != OGRERR_NONE)
    1514           0 :         return eErr;
    1515             : 
    1516         142 :     m_aosIgnoredFields = papszFields;
    1517             : 
    1518         142 :     return eErr;
    1519             : }
    1520             : 
    1521             : /************************************************************************/
    1522             : /*                             SyncToDisk()                             */
    1523             : /************************************************************************/
    1524             : 
    1525           1 : OGRErr OGRUnionLayer::SyncToDisk()
    1526             : {
    1527           3 :     for (auto &oLayer : m_apoSrcLayers)
    1528             :     {
    1529           2 :         if (oLayer.bModified)
    1530             :         {
    1531           1 :             oLayer->SyncToDisk();
    1532           1 :             oLayer.bModified = false;
    1533             :         }
    1534             :     }
    1535             : 
    1536           1 :     return OGRERR_NONE;
    1537             : }
    1538             : 
    1539             : #endif /* #ifndef DOXYGEN_SKIP */

Generated by: LCOV version 1.14