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