Coverage Report

Created: 2026-07-14 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_vector_select.cpp
Line
Count
Source
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
0
#define _(x) (x)
25
#endif
26
27
/************************************************************************/
28
/*        GDALVectorSelectAlgorithm::GDALVectorSelectAlgorithm()        */
29
/************************************************************************/
30
31
GDALVectorSelectAlgorithm::GDALVectorSelectAlgorithm(bool standaloneStep)
32
0
    : GDALVectorPipelineStepAlgorithm(
33
0
          NAME, DESCRIPTION, HELP_URL,
34
0
          ConstructorOptions()
35
0
              .SetStandaloneStep(standaloneStep)
36
0
              .SetOutputLayerNameAvailableInPipelineStep(true))
37
0
{
38
0
    AddActiveLayerArg(&m_activeLayer);
39
0
    if (!standaloneStep)
40
0
    {
41
0
        AddOutputLayerNameArg(/* hiddenForCLI = */ false,
42
0
                              /* shortNameOutputLayerAllowed = */ false);
43
0
    }
44
0
    AddArg("fields", 0, _("Fields to select (or exclude if --exclude)"),
45
0
           &m_fields)
46
0
        .SetDuplicateValuesAllowed(false)
47
0
        .SetPositional();
48
0
    AddArg("geometry", 0, _("Select default geometry field"), &m_defaultGeom);
49
0
    AddArg("exclude", 0, _("Exclude specified fields"), &m_exclude)
50
0
        .SetDuplicateValuesAllowed(false)
51
0
        .SetMutualExclusionGroup("exclude-ignore");
52
0
    AddArg("ignore-missing-fields", 0, _("Ignore missing fields"),
53
0
           &m_ignoreMissingFields)
54
0
        .SetMutualExclusionGroup("exclude-ignore");
55
56
0
    AddValidationAction(
57
0
        [this]()
58
0
        {
59
0
            if (!m_outputLayerName.empty() && m_activeLayer.empty() &&
60
0
                m_inputDataset.size() == 1)
61
0
            {
62
0
                auto poSrcDS = m_inputDataset[0].GetDatasetRef();
63
0
                if (poSrcDS && poSrcDS->GetLayerCount() > 1)
64
0
                {
65
0
                    ReportError(CE_Failure, CPLE_IllegalArg,
66
0
                                "Argument 'output-layer' cannot be used when "
67
0
                                "the input dataset has multiple layers, unless "
68
0
                                "argument 'active-layer' is specified");
69
0
                    return false;
70
0
                }
71
0
            }
72
0
            return true;
73
0
        });
74
0
}
75
76
namespace
77
{
78
79
/************************************************************************/
80
/*                    GDALVectorSelectAlgorithmLayer                    */
81
/************************************************************************/
82
83
class GDALVectorSelectAlgorithmLayer final
84
    : public GDALVectorPipelineOutputLayer
85
{
86
  private:
87
    const OGRFeatureDefnRefCountedPtr m_poFeatureDefn;
88
    std::vector<int> m_anMapSrcFieldsToDstFields{};
89
    std::vector<int> m_anMapDstGeomFieldsToSrcGeomFields{};
90
91
    CPL_DISALLOW_COPY_ASSIGN(GDALVectorSelectAlgorithmLayer)
92
93
    std::unique_ptr<OGRFeature>
94
    TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeature) const
95
0
    {
96
0
        auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn.get());
97
0
        poFeature->SetFID(poSrcFeature->GetFID());
98
0
        const auto styleString = poSrcFeature->GetStyleString();
99
0
        if (styleString)
100
0
            poFeature->SetStyleString(styleString);
101
0
        poFeature->SetFieldsFrom(poSrcFeature.get(),
102
0
                                 m_anMapSrcFieldsToDstFields.data(), false,
103
0
                                 false);
104
0
        int iDstGeomField = 0;
105
0
        for (int nSrcGeomField : m_anMapDstGeomFieldsToSrcGeomFields)
106
0
        {
107
0
            poFeature->SetGeomFieldDirectly(
108
0
                iDstGeomField, poSrcFeature->StealGeometry(nSrcGeomField));
109
0
            ++iDstGeomField;
110
0
        }
111
0
        return poFeature;
112
0
    }
113
114
    bool TranslateFeature(
115
        std::unique_ptr<OGRFeature> poSrcFeature,
116
        std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
117
0
    {
118
0
        auto poDstFeature = TranslateFeature(std::move(poSrcFeature));
119
0
        if (PassesFilters(poDstFeature.get()))
120
0
        {
121
0
            apoOutFeatures.push_back(std::move(poDstFeature));
122
0
        }
123
0
        return true;
124
0
    }
125
126
  public:
127
    explicit GDALVectorSelectAlgorithmLayer(
128
        OGRLayer &oSrcLayer, const std::string &osOutputLayerName)
129
0
        : GDALVectorPipelineOutputLayer(oSrcLayer),
130
0
          m_poFeatureDefn(OGRFeatureDefnRefCountedPtr::makeInstance(
131
0
              osOutputLayerName.empty() ? oSrcLayer.GetName()
132
0
                                        : osOutputLayerName.c_str()))
133
0
    {
134
0
        SetDescription(m_poFeatureDefn->GetName());
135
0
        SetMetadata(oSrcLayer.GetMetadata());
136
0
        m_poFeatureDefn->SetGeomType(wkbNone);
137
0
    }
138
139
    bool IncludeFields(const std::vector<std::string> &selectedFields,
140
                       bool bStrict)
141
0
    {
142
0
        std::set<std::string> oSetSelFields;
143
0
        std::set<std::string> oSetSelFieldsUC;
144
0
        for (const std::string &osFieldName : selectedFields)
145
0
        {
146
0
            oSetSelFields.insert(osFieldName);
147
0
            oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
148
0
        }
149
150
0
        std::set<std::string> oSetUsedSetFieldsUC;
151
152
0
        const auto poSrcLayerDefn = m_srcLayer.GetLayerDefn();
153
0
        for (const auto poSrcFieldDefn : poSrcLayerDefn->GetFields())
154
0
        {
155
0
            const auto oIter = oSetSelFieldsUC.find(
156
0
                CPLString(poSrcFieldDefn->GetNameRef()).toupper());
157
0
            if (oIter != oSetSelFieldsUC.end())
158
0
            {
159
0
                m_anMapSrcFieldsToDstFields.push_back(
160
0
                    m_poFeatureDefn->GetFieldCount());
161
0
                OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
162
0
                m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
163
0
                oSetUsedSetFieldsUC.insert(*oIter);
164
0
            }
165
0
            else
166
0
            {
167
0
                m_anMapSrcFieldsToDstFields.push_back(-1);
168
0
            }
169
0
        }
170
171
0
        for (const auto poSrcFieldDefn : poSrcLayerDefn->GetGeomFields())
172
0
        {
173
0
            const auto oIter = oSetSelFieldsUC.find(
174
0
                CPLString(poSrcFieldDefn->GetNameRef()).toupper());
175
0
            if (oIter != oSetSelFieldsUC.end())
176
0
            {
177
0
                m_anMapDstGeomFieldsToSrcGeomFields.push_back(
178
0
                    m_poFeatureDefn->GetGeomFieldCount());
179
0
                OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
180
0
                m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
181
0
                oSetUsedSetFieldsUC.insert(*oIter);
182
0
            }
183
0
        }
184
185
0
        const auto oIter = oSetSelFieldsUC.find(
186
0
            CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper());
187
0
        if (m_poFeatureDefn->GetGeomFieldCount() == 0 &&
188
0
            oIter != oSetSelFieldsUC.end() &&
189
0
            poSrcLayerDefn->GetGeomFieldCount() == 1)
190
0
        {
191
0
            const auto poSrcFieldDefn = poSrcLayerDefn->GetGeomFieldDefn(0);
192
0
            m_anMapDstGeomFieldsToSrcGeomFields.push_back(0);
193
0
            OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
194
0
            m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
195
0
            oSetUsedSetFieldsUC.insert(*oIter);
196
0
        }
197
198
0
        if (oSetUsedSetFieldsUC.size() != oSetSelFields.size())
199
0
        {
200
0
            for (const std::string &osName : oSetSelFields)
201
0
            {
202
0
                if (!cpl::contains(oSetUsedSetFieldsUC,
203
0
                                   CPLString(osName).toupper()))
204
0
                {
205
0
                    CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_AppDefined,
206
0
                             "Field '%s' does not exist in layer '%s'.%s",
207
0
                             osName.c_str(), m_srcLayer.GetDescription(),
208
0
                             bStrict ? " You may specify "
209
0
                                       "--ignore-missing-fields to skip it"
210
0
                                     : " It will be ignored");
211
0
                    if (bStrict)
212
0
                        return false;
213
0
                }
214
0
            }
215
0
        }
216
217
0
        return true;
218
0
    }
219
220
    void ExcludeFields(const std::vector<std::string> &fields)
221
0
    {
222
0
        std::set<std::string> oSetSelFields;
223
0
        std::set<std::string> oSetSelFieldsUC;
224
0
        for (const std::string &osFieldName : fields)
225
0
        {
226
0
            oSetSelFields.insert(osFieldName);
227
0
            oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
228
0
        }
229
230
0
        const auto poSrcLayerDefn = m_srcLayer.GetLayerDefn();
231
0
        for (const auto poSrcFieldDefn : poSrcLayerDefn->GetFields())
232
0
        {
233
0
            const auto oIter = oSetSelFieldsUC.find(
234
0
                CPLString(poSrcFieldDefn->GetNameRef()).toupper());
235
0
            if (oIter != oSetSelFieldsUC.end())
236
0
            {
237
0
                m_anMapSrcFieldsToDstFields.push_back(-1);
238
0
            }
239
0
            else
240
0
            {
241
0
                m_anMapSrcFieldsToDstFields.push_back(
242
0
                    m_poFeatureDefn->GetFieldCount());
243
0
                OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
244
0
                m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
245
0
            }
246
0
        }
247
248
0
        if (oSetSelFieldsUC.find(
249
0
                CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper()) !=
250
0
                oSetSelFieldsUC.end() &&
251
0
            poSrcLayerDefn->GetGeomFieldCount() == 1)
252
0
        {
253
            // exclude default geometry field
254
0
        }
255
0
        else
256
0
        {
257
0
            for (const auto poSrcFieldDefn : poSrcLayerDefn->GetGeomFields())
258
0
            {
259
0
                const auto oIter = oSetSelFieldsUC.find(
260
0
                    CPLString(poSrcFieldDefn->GetNameRef()).toupper());
261
0
                if (oIter == oSetSelFieldsUC.end())
262
0
                {
263
0
                    m_anMapDstGeomFieldsToSrcGeomFields.push_back(
264
0
                        m_poFeatureDefn->GetGeomFieldCount());
265
0
                    OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
266
0
                    m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
267
0
                }
268
0
            }
269
0
        }
270
0
    }
271
272
    const OGRFeatureDefn *GetLayerDefn() const override
273
0
    {
274
0
        return m_poFeatureDefn.get();
275
0
    }
276
277
    GIntBig GetFeatureCount(int bForce) override
278
0
    {
279
0
        if (!m_poAttrQuery && !m_poFilterGeom)
280
0
            return m_srcLayer.GetFeatureCount(bForce);
281
0
        return OGRLayer::GetFeatureCount(bForce);
282
0
    }
283
284
    OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
285
                      bool bForce) override
286
0
    {
287
0
        return m_srcLayer.GetExtent(iGeomField, psExtent, bForce);
288
0
    }
289
290
    OGRFeature *GetFeature(GIntBig nFID) override
291
0
    {
292
0
        auto poSrcFeature =
293
0
            std::unique_ptr<OGRFeature>(m_srcLayer.GetFeature(nFID));
294
0
        if (!poSrcFeature)
295
0
            return nullptr;
296
0
        return TranslateFeature(std::move(poSrcFeature)).release();
297
0
    }
298
299
    int TestCapability(const char *pszCap) const override
300
0
    {
301
0
        if (EQUAL(pszCap, OLCRandomRead) || EQUAL(pszCap, OLCCurveGeometries) ||
302
0
            EQUAL(pszCap, OLCMeasuredGeometries) ||
303
0
            EQUAL(pszCap, OLCZGeometries) ||
304
0
            (EQUAL(pszCap, OLCFastFeatureCount) && !m_poAttrQuery &&
305
0
             !m_poFilterGeom) ||
306
0
            EQUAL(pszCap, OLCFastGetExtent) || EQUAL(pszCap, OLCStringsAsUTF8))
307
0
        {
308
0
            return m_srcLayer.TestCapability(pszCap);
309
0
        }
310
0
        return false;
311
0
    }
312
};
313
314
}  // namespace
315
316
/************************************************************************/
317
/*                 GDALVectorSelectAlgorithm::RunStep()                 */
318
/************************************************************************/
319
320
bool GDALVectorSelectAlgorithm::RunStep(GDALPipelineStepRunContext &)
321
0
{
322
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
323
0
    CPLAssert(poSrcDS);
324
325
0
    CPLAssert(m_outputDataset.GetName().empty());
326
0
    CPLAssert(!m_outputDataset.GetDatasetRef());
327
328
0
    auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
329
330
0
    if (m_defaultGeom &&
331
0
        std::find(m_fields.begin(), m_fields.end(),
332
0
                  OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME) == m_fields.end())
333
0
    {
334
0
        m_fields.emplace_back(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
335
0
    }
336
0
    if (m_fields.empty())
337
0
    {
338
0
        CPLError(CE_Failure, CPLE_AppDefined,
339
0
                 "Must specify --fields and/or --geometry");
340
0
        return false;
341
0
    }
342
343
0
    for (auto &&poSrcLayer : poSrcDS->GetLayers())
344
0
    {
345
0
        if (m_activeLayer.empty() ||
346
0
            m_activeLayer == poSrcLayer->GetDescription())
347
0
        {
348
0
            auto poLayer = std::make_unique<GDALVectorSelectAlgorithmLayer>(
349
0
                *poSrcLayer, m_outputLayerName);
350
0
            if (m_exclude)
351
0
            {
352
0
                poLayer->ExcludeFields(m_fields);
353
0
            }
354
0
            else
355
0
            {
356
0
                if (!poLayer->IncludeFields(m_fields, !m_ignoreMissingFields))
357
0
                    return false;
358
0
            }
359
0
            outDS->AddLayer(*poSrcLayer, std::move(poLayer));
360
0
        }
361
0
        else
362
0
        {
363
0
            outDS->AddLayer(
364
0
                *poSrcLayer,
365
0
                std::make_unique<GDALVectorPipelinePassthroughLayer>(
366
0
                    *poSrcLayer));
367
0
        }
368
0
    }
369
370
0
    m_outputDataset.Set(std::move(outDS));
371
372
0
    return true;
373
0
}
374
375
0
GDALVectorSelectAlgorithmStandalone::~GDALVectorSelectAlgorithmStandalone() =
376
    default;
377
378
//! @endcond