Coverage Report

Created: 2026-04-01 06:20

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