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

Generated by: LCOV version 1.14