LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_select.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 151 153 98.7 %
Date: 2026-02-21 16:21:44 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "select" step of "vector pipeline"
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_vector_select.h"
      14             : 
      15             : #include "gdal_priv.h"
      16             : #include "ogrsf_frmts.h"
      17             : #include "ogr_p.h"
      18             : 
      19             : #include <set>
      20             : 
      21             : //! @cond Doxygen_Suppress
      22             : 
      23             : #ifndef _
      24             : #define _(x) (x)
      25             : #endif
      26             : 
      27             : /************************************************************************/
      28             : /*        GDALVectorSelectAlgorithm::GDALVectorSelectAlgorithm()        */
      29             : /************************************************************************/
      30             : 
      31          51 : GDALVectorSelectAlgorithm::GDALVectorSelectAlgorithm(bool standaloneStep)
      32             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      33          51 :                                       standaloneStep)
      34             : {
      35          51 :     if (!standaloneStep)
      36             :     {
      37          35 :         AddOutputLayerNameArg(/* hiddenForCLI = */ false,
      38             :                               /* shortNameOutputLayerAllowed = */ false);
      39             :     }
      40          51 :     AddActiveLayerArg(&m_activeLayer);
      41             :     AddArg("fields", 0, _("Fields to select (or exclude if --exclude)"),
      42         102 :            &m_fields)
      43          51 :         .SetPositional()
      44          51 :         .SetRequired();
      45         102 :     AddArg("exclude", 0, _("Exclude specified fields"), &m_exclude)
      46          51 :         .SetMutualExclusionGroup("exclude-ignore");
      47             :     AddArg("ignore-missing-fields", 0, _("Ignore missing fields"),
      48         102 :            &m_ignoreMissingFields)
      49          51 :         .SetMutualExclusionGroup("exclude-ignore");
      50          51 : }
      51             : 
      52             : namespace
      53             : {
      54             : 
      55             : /************************************************************************/
      56             : /*                    GDALVectorSelectAlgorithmLayer                    */
      57             : /************************************************************************/
      58             : 
      59             : class GDALVectorSelectAlgorithmLayer final
      60             :     : public GDALVectorPipelineOutputLayer
      61             : {
      62             :   private:
      63             :     OGRFeatureDefn *const m_poFeatureDefn = nullptr;
      64             :     std::vector<int> m_anMapSrcFieldsToDstFields{};
      65             :     std::vector<int> m_anMapDstGeomFieldsToSrcGeomFields{};
      66             : 
      67             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorSelectAlgorithmLayer)
      68             : 
      69             :     std::unique_ptr<OGRFeature>
      70         102 :     TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeature) const
      71             :     {
      72         102 :         auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
      73         102 :         poFeature->SetFID(poSrcFeature->GetFID());
      74         102 :         const auto styleString = poSrcFeature->GetStyleString();
      75         102 :         if (styleString)
      76           0 :             poFeature->SetStyleString(styleString);
      77         102 :         poFeature->SetFieldsFrom(poSrcFeature.get(),
      78             :                                  m_anMapSrcFieldsToDstFields.data(), false,
      79             :                                  false);
      80         102 :         int iDstGeomField = 0;
      81         184 :         for (int nSrcGeomField : m_anMapDstGeomFieldsToSrcGeomFields)
      82             :         {
      83          82 :             poFeature->SetGeomFieldDirectly(
      84             :                 iDstGeomField, poSrcFeature->StealGeometry(nSrcGeomField));
      85          82 :             ++iDstGeomField;
      86             :         }
      87         102 :         return poFeature;
      88             :     }
      89             : 
      90         101 :     void TranslateFeature(
      91             :         std::unique_ptr<OGRFeature> poSrcFeature,
      92             :         std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
      93             :     {
      94         101 :         apoOutFeatures.push_back(TranslateFeature(std::move(poSrcFeature)));
      95         101 :     }
      96             : 
      97             :   public:
      98          10 :     explicit GDALVectorSelectAlgorithmLayer(
      99             :         OGRLayer &oSrcLayer, const std::string &osOutputLayerName)
     100          10 :         : GDALVectorPipelineOutputLayer(oSrcLayer),
     101          10 :           m_poFeatureDefn(new OGRFeatureDefn(osOutputLayerName.empty()
     102          10 :                                                  ? oSrcLayer.GetName()
     103          20 :                                                  : osOutputLayerName.c_str()))
     104             :     {
     105          10 :         SetDescription(m_poFeatureDefn->GetName());
     106          10 :         SetMetadata(oSrcLayer.GetMetadata());
     107          10 :         m_poFeatureDefn->SetGeomType(wkbNone);
     108          10 :         m_poFeatureDefn->Reference();
     109          10 :     }
     110             : 
     111          20 :     ~GDALVectorSelectAlgorithmLayer() override
     112          10 :     {
     113          10 :         m_poFeatureDefn->Release();
     114          20 :     }
     115             : 
     116           6 :     bool IncludeFields(const std::vector<std::string> &selectedFields,
     117             :                        bool bStrict)
     118             :     {
     119          12 :         std::set<std::string> oSetSelFields;
     120          12 :         std::set<std::string> oSetSelFieldsUC;
     121          16 :         for (const std::string &osFieldName : selectedFields)
     122             :         {
     123          10 :             oSetSelFields.insert(osFieldName);
     124          10 :             oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
     125             :         }
     126             : 
     127          12 :         std::set<std::string> oSetUsedSetFieldsUC;
     128             : 
     129           6 :         const auto poSrcLayerDefn = m_srcLayer.GetLayerDefn();
     130          21 :         for (const auto poSrcFieldDefn : poSrcLayerDefn->GetFields())
     131             :         {
     132             :             const auto oIter = oSetSelFieldsUC.find(
     133          15 :                 CPLString(poSrcFieldDefn->GetNameRef()).toupper());
     134          15 :             if (oIter != oSetSelFieldsUC.end())
     135             :             {
     136          10 :                 m_anMapSrcFieldsToDstFields.push_back(
     137           5 :                     m_poFeatureDefn->GetFieldCount());
     138          10 :                 OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
     139           5 :                 m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
     140           5 :                 oSetUsedSetFieldsUC.insert(*oIter);
     141             :             }
     142             :             else
     143             :             {
     144          10 :                 m_anMapSrcFieldsToDstFields.push_back(-1);
     145             :             }
     146             :         }
     147             : 
     148          13 :         for (const auto poSrcFieldDefn : poSrcLayerDefn->GetGeomFields())
     149             :         {
     150             :             const auto oIter = oSetSelFieldsUC.find(
     151           7 :                 CPLString(poSrcFieldDefn->GetNameRef()).toupper());
     152           7 :             if (oIter != oSetSelFieldsUC.end())
     153             :             {
     154           2 :                 m_anMapDstGeomFieldsToSrcGeomFields.push_back(
     155           1 :                     m_poFeatureDefn->GetGeomFieldCount());
     156           2 :                 OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
     157           1 :                 m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
     158           1 :                 oSetUsedSetFieldsUC.insert(*oIter);
     159             :             }
     160             :         }
     161             : 
     162             :         const auto oIter = oSetSelFieldsUC.find(
     163           6 :             CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper());
     164          11 :         if (m_poFeatureDefn->GetGeomFieldCount() == 0 &&
     165          11 :             oIter != oSetSelFieldsUC.end() &&
     166           2 :             poSrcLayerDefn->GetGeomFieldCount() == 1)
     167             :         {
     168           2 :             const auto poSrcFieldDefn = poSrcLayerDefn->GetGeomFieldDefn(0);
     169           2 :             m_anMapDstGeomFieldsToSrcGeomFields.push_back(0);
     170           4 :             OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
     171           2 :             m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
     172           2 :             oSetUsedSetFieldsUC.insert(*oIter);
     173             :         }
     174             : 
     175           6 :         if (oSetUsedSetFieldsUC.size() != oSetSelFields.size())
     176             :         {
     177           6 :             for (const std::string &osName : oSetSelFields)
     178             :             {
     179          15 :                 if (!cpl::contains(oSetUsedSetFieldsUC,
     180           5 :                                    CPLString(osName).toupper()))
     181             :                 {
     182           4 :                     CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_AppDefined,
     183             :                              "Field '%s' does not exist in layer '%s'.%s",
     184           2 :                              osName.c_str(), m_srcLayer.GetDescription(),
     185             :                              bStrict ? " You may specify "
     186             :                                        "--ignore-missing-fields to skip it"
     187             :                                      : " It will be ignored");
     188           2 :                     if (bStrict)
     189           1 :                         return false;
     190             :                 }
     191             :             }
     192             :         }
     193             : 
     194           5 :         return true;
     195             :     }
     196             : 
     197           4 :     void ExcludeFields(const std::vector<std::string> &fields)
     198             :     {
     199           8 :         std::set<std::string> oSetSelFields;
     200           8 :         std::set<std::string> oSetSelFieldsUC;
     201           9 :         for (const std::string &osFieldName : fields)
     202             :         {
     203           5 :             oSetSelFields.insert(osFieldName);
     204           5 :             oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
     205             :         }
     206             : 
     207           4 :         const auto poSrcLayerDefn = m_srcLayer.GetLayerDefn();
     208          16 :         for (const auto poSrcFieldDefn : poSrcLayerDefn->GetFields())
     209             :         {
     210             :             const auto oIter = oSetSelFieldsUC.find(
     211          12 :                 CPLString(poSrcFieldDefn->GetNameRef()).toupper());
     212          12 :             if (oIter != oSetSelFieldsUC.end())
     213             :             {
     214           1 :                 m_anMapSrcFieldsToDstFields.push_back(-1);
     215             :             }
     216             :             else
     217             :             {
     218          22 :                 m_anMapSrcFieldsToDstFields.push_back(
     219          11 :                     m_poFeatureDefn->GetFieldCount());
     220          22 :                 OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
     221          11 :                 m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
     222             :             }
     223             :         }
     224             : 
     225           0 :         if (oSetSelFieldsUC.find(
     226           8 :                 CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper()) !=
     227          13 :                 oSetSelFieldsUC.end() &&
     228           1 :             poSrcLayerDefn->GetGeomFieldCount() == 1)
     229             :         {
     230             :             // exclude default geometry field
     231             :         }
     232             :         else
     233             :         {
     234           6 :             for (const auto poSrcFieldDefn : poSrcLayerDefn->GetGeomFields())
     235             :             {
     236             :                 const auto oIter = oSetSelFieldsUC.find(
     237           3 :                     CPLString(poSrcFieldDefn->GetNameRef()).toupper());
     238           3 :                 if (oIter == oSetSelFieldsUC.end())
     239             :                 {
     240           4 :                     m_anMapDstGeomFieldsToSrcGeomFields.push_back(
     241           2 :                         m_poFeatureDefn->GetGeomFieldCount());
     242           4 :                     OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
     243           2 :                     m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
     244             :                 }
     245             :             }
     246             :         }
     247           4 :     }
     248             : 
     249          51 :     const OGRFeatureDefn *GetLayerDefn() const override
     250             :     {
     251          51 :         return m_poFeatureDefn;
     252             :     }
     253             : 
     254           3 :     GIntBig GetFeatureCount(int bForce) override
     255             :     {
     256           3 :         if (!m_poAttrQuery && !m_poFilterGeom)
     257           1 :             return m_srcLayer.GetFeatureCount(bForce);
     258           2 :         return OGRLayer::GetFeatureCount(bForce);
     259             :     }
     260             : 
     261           2 :     OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
     262             :                       bool bForce) override
     263             :     {
     264           2 :         return m_srcLayer.GetExtent(iGeomField, psExtent, bForce);
     265             :     }
     266             : 
     267           2 :     OGRFeature *GetFeature(GIntBig nFID) override
     268             :     {
     269             :         auto poSrcFeature =
     270           4 :             std::unique_ptr<OGRFeature>(m_srcLayer.GetFeature(nFID));
     271           2 :         if (!poSrcFeature)
     272           1 :             return nullptr;
     273           1 :         return TranslateFeature(std::move(poSrcFeature)).release();
     274             :     }
     275             : 
     276          12 :     int TestCapability(const char *pszCap) const override
     277             :     {
     278          12 :         if (EQUAL(pszCap, OLCRandomRead) || EQUAL(pszCap, OLCCurveGeometries) ||
     279          12 :             EQUAL(pszCap, OLCMeasuredGeometries) ||
     280          12 :             EQUAL(pszCap, OLCZGeometries) ||
     281          12 :             (EQUAL(pszCap, OLCFastFeatureCount) && !m_poAttrQuery &&
     282           2 :              !m_poFilterGeom) ||
     283          11 :             EQUAL(pszCap, OLCFastGetExtent) || EQUAL(pszCap, OLCStringsAsUTF8))
     284             :         {
     285           2 :             return m_srcLayer.TestCapability(pszCap);
     286             :         }
     287          10 :         return false;
     288             :     }
     289             : };
     290             : 
     291             : }  // namespace
     292             : 
     293             : /************************************************************************/
     294             : /*                 GDALVectorSelectAlgorithm::RunStep()                 */
     295             : /************************************************************************/
     296             : 
     297          10 : bool GDALVectorSelectAlgorithm::RunStep(GDALPipelineStepRunContext &)
     298             : {
     299          10 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     300          10 :     CPLAssert(poSrcDS);
     301             : 
     302          10 :     CPLAssert(m_outputDataset.GetName().empty());
     303          10 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     304             : 
     305          20 :     auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
     306             : 
     307          20 :     for (auto &&poSrcLayer : poSrcDS->GetLayers())
     308             :     {
     309          13 :         if (m_activeLayer.empty() ||
     310           2 :             m_activeLayer == poSrcLayer->GetDescription())
     311             :         {
     312             :             auto poLayer = std::make_unique<GDALVectorSelectAlgorithmLayer>(
     313          10 :                 *poSrcLayer, m_outputLayerName);
     314          10 :             if (m_exclude)
     315             :             {
     316           4 :                 poLayer->ExcludeFields(m_fields);
     317             :             }
     318             :             else
     319             :             {
     320           6 :                 if (!poLayer->IncludeFields(m_fields, !m_ignoreMissingFields))
     321           1 :                     return false;
     322             :             }
     323           9 :             outDS->AddLayer(*poSrcLayer, std::move(poLayer));
     324             :         }
     325             :         else
     326             :         {
     327           2 :             outDS->AddLayer(
     328             :                 *poSrcLayer,
     329           2 :                 std::make_unique<GDALVectorPipelinePassthroughLayer>(
     330             :                     *poSrcLayer));
     331             :         }
     332             :     }
     333             : 
     334           9 :     m_outputDataset.Set(std::move(outDS));
     335             : 
     336           9 :     return true;
     337             : }
     338             : 
     339             : GDALVectorSelectAlgorithmStandalone::~GDALVectorSelectAlgorithmStandalone() =
     340             :     default;
     341             : 
     342             : //! @endcond

Generated by: LCOV version 1.14