LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrunionlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 627 737 85.1 %
Date: 2026-01-09 05:19:41 Functions: 33 35 94.3 %

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

Generated by: LCOV version 1.14