Coverage Report

Created: 2026-02-14 09:00

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