LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_write.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 113 116 97.4 %
Date: 2026-03-01 17:56:51 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "write" 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_write.h"
      14             : #include "cpl_string.h"
      15             : #include "gdal_utils.h"
      16             : #include "gdal_priv.h"
      17             : 
      18             : #ifndef _
      19             : #define _(x) (x)
      20             : #endif
      21             : 
      22             : //! @cond Doxygen_Suppress
      23             : 
      24             : /************************************************************************/
      25             : /*         GDALVectorWriteAlgorithm::GDALVectorWriteAlgorithm()         */
      26             : /************************************************************************/
      27             : 
      28         492 : GDALVectorWriteAlgorithm::GDALVectorWriteAlgorithm()
      29             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      30           0 :                                       ConstructorOptions()
      31         492 :                                           .SetStandaloneStep(false)
      32         984 :                                           .SetNoCreateEmptyLayersArgument(true))
      33             : {
      34         492 :     AddVectorOutputArgs(/* hiddenForCLI = */ false,
      35             :                         /* shortNameOutputLayerAllowed=*/true);
      36         492 : }
      37             : 
      38             : /************************************************************************/
      39             : /*                 GDALVectorWriteAlgorithm::RunStep()                  */
      40             : /************************************************************************/
      41             : 
      42             : namespace
      43             : {
      44          46 : class OGRReadBufferedLayer
      45             :     : public OGRLayer,
      46             :       public OGRGetNextFeatureThroughRaw<OGRReadBufferedLayer>
      47             : {
      48             :   public:
      49          23 :     explicit OGRReadBufferedLayer(OGRLayer &srcLayer)
      50          23 :         : m_srcLayer(srcLayer), m_poFeature(nullptr)
      51             :     {
      52          23 :         m_poFeature.reset(m_srcLayer.GetNextFeature());
      53          23 :     }
      54             : 
      55             :     ~OGRReadBufferedLayer() override;
      56             : 
      57           2 :     const char *GetDescription() const override
      58             :     {
      59           2 :         return m_srcLayer.GetDescription();
      60             :     }
      61             : 
      62          27 :     GIntBig GetFeatureCount(int bForce) override
      63             :     {
      64          27 :         if (m_poAttrQuery == nullptr && m_poFilterGeom == nullptr)
      65             :         {
      66          17 :             return m_srcLayer.GetFeatureCount(bForce);
      67             :         }
      68             : 
      69          10 :         return OGRLayer::GetFeatureCount(bForce);
      70             :     }
      71             : 
      72         327 :     const OGRFeatureDefn *GetLayerDefn() const override
      73             :     {
      74         327 :         return m_srcLayer.GetLayerDefn();
      75             :     }
      76             : 
      77         205 :     OGRFeature *GetNextRawFeature()
      78             :     {
      79         205 :         auto ret = m_poFeature.release();
      80         205 :         m_poFeature.reset(m_srcLayer.GetNextFeature());
      81         205 :         return ret;
      82             :     }
      83             : 
      84         171 :     DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(OGRReadBufferedLayer)
      85             : 
      86           4 :     OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
      87             :                       bool bForce) override
      88             :     {
      89           4 :         return m_srcLayer.GetExtent(iGeomField, psExtent, bForce);
      90             :     }
      91             : 
      92           0 :     OGRErr IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent,
      93             :                         bool bForce) override
      94             :     {
      95           0 :         return m_srcLayer.GetExtent3D(iGeomField, psExtent, bForce);
      96             :     }
      97             : 
      98          23 :     const OGRFeature *PeekNextFeature() const
      99             :     {
     100          23 :         return m_poFeature.get();
     101             :     }
     102             : 
     103          70 :     int TestCapability(const char *pszCap) const override
     104             :     {
     105          70 :         if (EQUAL(pszCap, OLCFastFeatureCount) ||
     106          70 :             EQUAL(pszCap, OLCFastGetExtent) ||
     107          67 :             EQUAL(pszCap, OLCFastGetExtent3D) ||
     108          67 :             EQUAL(pszCap, OLCZGeometries) ||
     109          61 :             EQUAL(pszCap, OLCMeasuredGeometries) ||
     110          53 :             EQUAL(pszCap, OLCCurveGeometries))
     111             :         {
     112          25 :             return m_srcLayer.TestCapability(pszCap);
     113             :         }
     114             : 
     115          45 :         return false;
     116             :     }
     117             : 
     118         168 :     void ResetReading() override
     119             :     {
     120         168 :         m_srcLayer.ResetReading();
     121         168 :         m_poFeature.reset(m_srcLayer.GetNextFeature());
     122         168 :     }
     123             : 
     124             :   private:
     125             :     OGRLayer &m_srcLayer;
     126             :     std::unique_ptr<OGRFeature> m_poFeature;
     127             : };
     128             : 
     129             : OGRReadBufferedLayer::~OGRReadBufferedLayer() = default;
     130             : 
     131             : class GDALReadBufferedDataset final : public GDALDataset
     132             : {
     133             :   public:
     134          10 :     explicit GDALReadBufferedDataset(GDALDataset &srcDS) : m_srcDS(srcDS)
     135             :     {
     136          10 :         m_srcDS.Reference();
     137             : 
     138          33 :         for (int i = 0; i < srcDS.GetLayerCount(); i++)
     139             :         {
     140             :             auto poLayer =
     141          46 :                 std::make_unique<OGRReadBufferedLayer>(*srcDS.GetLayer(i));
     142          23 :             if (poLayer->PeekNextFeature())
     143             :             {
     144          14 :                 m_layers.push_back(std::move(poLayer));
     145             :             }
     146             :         }
     147          10 :     }
     148             : 
     149             :     ~GDALReadBufferedDataset() override;
     150             : 
     151          71 :     int GetLayerCount() const override
     152             :     {
     153          71 :         return static_cast<int>(m_layers.size());
     154             :     }
     155             : 
     156          54 :     const OGRLayer *GetLayer(int nLayer) const override
     157             :     {
     158          54 :         if (nLayer < 0 || nLayer >= static_cast<int>(m_layers.size()))
     159             :         {
     160           4 :             return nullptr;
     161             :         }
     162          50 :         return m_layers[nLayer].get();
     163             :     }
     164             : 
     165             :   private:
     166             :     GDALDataset &m_srcDS;
     167             :     std::vector<std::unique_ptr<OGRReadBufferedLayer>> m_layers{};
     168             : };
     169             : 
     170          20 : GDALReadBufferedDataset::~GDALReadBufferedDataset()
     171             : {
     172          10 :     m_srcDS.Release();
     173          20 : }
     174             : 
     175             : }  // namespace
     176             : 
     177         371 : bool GDALVectorWriteAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     178             : {
     179         371 :     auto pfnProgress = ctxt.m_pfnProgress;
     180         371 :     auto pProgressData = ctxt.m_pProgressData;
     181         371 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     182         371 :     CPLAssert(poSrcDS);
     183             : 
     184         371 :     std::unique_ptr<GDALDataset> poReadBufferedDataset;
     185             : 
     186         371 :     if (m_noCreateEmptyLayers)
     187             :     {
     188          10 :         if (poSrcDS->TestCapability(ODsCRandomLayerRead))
     189             :         {
     190           1 :             CPLError(
     191             :                 CE_Warning, CPLE_AppDefined,
     192             :                 "Source dataset supports random-layer reading, but this "
     193             :                 "is not compatible with --no-create-empty-layers. Attempting "
     194             :                 "to read features by layer, but this may fail if the "
     195             :                 "source dataset is large.");
     196             :         }
     197             : 
     198             :         poReadBufferedDataset =
     199          10 :             std::make_unique<GDALReadBufferedDataset>(*poSrcDS);
     200             : 
     201          10 :         if (m_format == "stream")
     202             :         {
     203           8 :             m_outputDataset.Set(std::move(poReadBufferedDataset));
     204           8 :             return true;
     205             :         }
     206             : 
     207           2 :         poSrcDS = poReadBufferedDataset.get();
     208             :     }
     209             : 
     210         363 :     if (m_format == "stream")
     211             :     {
     212         155 :         m_outputDataset.Set(poSrcDS);
     213         155 :         return true;
     214             :     }
     215             : 
     216         416 :     CPLStringList aosOptions;
     217         208 :     aosOptions.AddString("--invoked-from-gdal-algorithm");
     218         208 :     if (!m_overwrite)
     219             :     {
     220         198 :         aosOptions.AddString("--no-overwrite");
     221             :     }
     222         208 :     if (m_overwriteLayer)
     223             :     {
     224           5 :         aosOptions.AddString("-overwrite");
     225             :     }
     226         208 :     if (m_appendLayer)
     227             :     {
     228           3 :         aosOptions.AddString("-append");
     229             :     }
     230         208 :     if (m_upsert)
     231             :     {
     232           2 :         aosOptions.AddString("-upsert");
     233             :     }
     234         208 :     if (!m_format.empty())
     235             :     {
     236         125 :         aosOptions.AddString("-of");
     237         125 :         aosOptions.AddString(m_format.c_str());
     238             :     }
     239         210 :     for (const auto &co : m_creationOptions)
     240             :     {
     241           2 :         aosOptions.AddString("-dsco");
     242           2 :         aosOptions.AddString(co.c_str());
     243             :     }
     244         212 :     for (const auto &co : m_layerCreationOptions)
     245             :     {
     246           4 :         aosOptions.AddString("-lco");
     247           4 :         aosOptions.AddString(co.c_str());
     248             :     }
     249         208 :     if (!m_outputLayerName.empty())
     250             :     {
     251           5 :         aosOptions.AddString("-nln");
     252           5 :         aosOptions.AddString(m_outputLayerName.c_str());
     253             :     }
     254         208 :     if (pfnProgress && pfnProgress != GDALDummyProgress)
     255             :     {
     256           9 :         aosOptions.AddString("-progress");
     257             :     }
     258         208 :     if (m_skipErrors)
     259             :     {
     260           2 :         aosOptions.AddString("-skipfailures");
     261             :     }
     262             : 
     263         208 :     GDALDataset *poRetDS = nullptr;
     264             :     GDALDatasetH hOutDS =
     265         208 :         GDALDataset::ToHandle(m_outputDataset.GetDatasetRef());
     266             :     GDALVectorTranslateOptions *psOptions =
     267         208 :         GDALVectorTranslateOptionsNew(aosOptions.List(), nullptr);
     268         208 :     if (psOptions)
     269             :     {
     270         208 :         GDALVectorTranslateOptionsSetProgress(psOptions, pfnProgress,
     271             :                                               pProgressData);
     272             : 
     273         208 :         GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
     274         208 :         poRetDS = GDALDataset::FromHandle(
     275         208 :             GDALVectorTranslate(m_outputDataset.GetName().c_str(), hOutDS, 1,
     276             :                                 &hSrcDS, psOptions, nullptr));
     277         208 :         GDALVectorTranslateOptionsFree(psOptions);
     278             :     }
     279             : 
     280         208 :     if (!poRetDS)
     281             :     {
     282          14 :         return false;
     283             :     }
     284             : 
     285         194 :     if (!hOutDS)
     286             :     {
     287         183 :         m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
     288             :     }
     289             : 
     290         194 :     return true;
     291             : }
     292             : 
     293             : //! @endcond

Generated by: LCOV version 1.14