Coverage Report

Created: 2026-04-10 07:04

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
    const OGRFeatureDefnRefCountedPtr m_poFeatureDefn;
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.get());
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(OGRFeatureDefnRefCountedPtr::makeInstance(
104
0
              osOutputLayerName.empty() ? 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
    }
111
112
    bool IncludeFields(const std::vector<std::string> &selectedFields,
113
                       bool bStrict)
114
0
    {
115
0
        std::set<std::string> oSetSelFields;
116
0
        std::set<std::string> oSetSelFieldsUC;
117
0
        for (const std::string &osFieldName : selectedFields)
118
0
        {
119
0
            oSetSelFields.insert(osFieldName);
120
0
            oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
121
0
        }
122
123
0
        std::set<std::string> oSetUsedSetFieldsUC;
124
125
0
        const auto poSrcLayerDefn = m_srcLayer.GetLayerDefn();
126
0
        for (const auto poSrcFieldDefn : poSrcLayerDefn->GetFields())
127
0
        {
128
0
            const auto oIter = oSetSelFieldsUC.find(
129
0
                CPLString(poSrcFieldDefn->GetNameRef()).toupper());
130
0
            if (oIter != oSetSelFieldsUC.end())
131
0
            {
132
0
                m_anMapSrcFieldsToDstFields.push_back(
133
0
                    m_poFeatureDefn->GetFieldCount());
134
0
                OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
135
0
                m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
136
0
                oSetUsedSetFieldsUC.insert(*oIter);
137
0
            }
138
0
            else
139
0
            {
140
0
                m_anMapSrcFieldsToDstFields.push_back(-1);
141
0
            }
142
0
        }
143
144
0
        for (const auto poSrcFieldDefn : poSrcLayerDefn->GetGeomFields())
145
0
        {
146
0
            const auto oIter = oSetSelFieldsUC.find(
147
0
                CPLString(poSrcFieldDefn->GetNameRef()).toupper());
148
0
            if (oIter != oSetSelFieldsUC.end())
149
0
            {
150
0
                m_anMapDstGeomFieldsToSrcGeomFields.push_back(
151
0
                    m_poFeatureDefn->GetGeomFieldCount());
152
0
                OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
153
0
                m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
154
0
                oSetUsedSetFieldsUC.insert(*oIter);
155
0
            }
156
0
        }
157
158
0
        const auto oIter = oSetSelFieldsUC.find(
159
0
            CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper());
160
0
        if (m_poFeatureDefn->GetGeomFieldCount() == 0 &&
161
0
            oIter != oSetSelFieldsUC.end() &&
162
0
            poSrcLayerDefn->GetGeomFieldCount() == 1)
163
0
        {
164
0
            const auto poSrcFieldDefn = poSrcLayerDefn->GetGeomFieldDefn(0);
165
0
            m_anMapDstGeomFieldsToSrcGeomFields.push_back(0);
166
0
            OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
167
0
            m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
168
0
            oSetUsedSetFieldsUC.insert(*oIter);
169
0
        }
170
171
0
        if (oSetUsedSetFieldsUC.size() != oSetSelFields.size())
172
0
        {
173
0
            for (const std::string &osName : oSetSelFields)
174
0
            {
175
0
                if (!cpl::contains(oSetUsedSetFieldsUC,
176
0
                                   CPLString(osName).toupper()))
177
0
                {
178
0
                    CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_AppDefined,
179
0
                             "Field '%s' does not exist in layer '%s'.%s",
180
0
                             osName.c_str(), m_srcLayer.GetDescription(),
181
0
                             bStrict ? " You may specify "
182
0
                                       "--ignore-missing-fields to skip it"
183
0
                                     : " It will be ignored");
184
0
                    if (bStrict)
185
0
                        return false;
186
0
                }
187
0
            }
188
0
        }
189
190
0
        return true;
191
0
    }
192
193
    void ExcludeFields(const std::vector<std::string> &fields)
194
0
    {
195
0
        std::set<std::string> oSetSelFields;
196
0
        std::set<std::string> oSetSelFieldsUC;
197
0
        for (const std::string &osFieldName : fields)
198
0
        {
199
0
            oSetSelFields.insert(osFieldName);
200
0
            oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
201
0
        }
202
203
0
        const auto poSrcLayerDefn = m_srcLayer.GetLayerDefn();
204
0
        for (const auto poSrcFieldDefn : poSrcLayerDefn->GetFields())
205
0
        {
206
0
            const auto oIter = oSetSelFieldsUC.find(
207
0
                CPLString(poSrcFieldDefn->GetNameRef()).toupper());
208
0
            if (oIter != oSetSelFieldsUC.end())
209
0
            {
210
0
                m_anMapSrcFieldsToDstFields.push_back(-1);
211
0
            }
212
0
            else
213
0
            {
214
0
                m_anMapSrcFieldsToDstFields.push_back(
215
0
                    m_poFeatureDefn->GetFieldCount());
216
0
                OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
217
0
                m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
218
0
            }
219
0
        }
220
221
0
        if (oSetSelFieldsUC.find(
222
0
                CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper()) !=
223
0
                oSetSelFieldsUC.end() &&
224
0
            poSrcLayerDefn->GetGeomFieldCount() == 1)
225
0
        {
226
            // exclude default geometry field
227
0
        }
228
0
        else
229
0
        {
230
0
            for (const auto poSrcFieldDefn : poSrcLayerDefn->GetGeomFields())
231
0
            {
232
0
                const auto oIter = oSetSelFieldsUC.find(
233
0
                    CPLString(poSrcFieldDefn->GetNameRef()).toupper());
234
0
                if (oIter == oSetSelFieldsUC.end())
235
0
                {
236
0
                    m_anMapDstGeomFieldsToSrcGeomFields.push_back(
237
0
                        m_poFeatureDefn->GetGeomFieldCount());
238
0
                    OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
239
0
                    m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
240
0
                }
241
0
            }
242
0
        }
243
0
    }
244
245
    const OGRFeatureDefn *GetLayerDefn() const override
246
0
    {
247
0
        return m_poFeatureDefn.get();
248
0
    }
249
250
    GIntBig GetFeatureCount(int bForce) override
251
0
    {
252
0
        if (!m_poAttrQuery && !m_poFilterGeom)
253
0
            return m_srcLayer.GetFeatureCount(bForce);
254
0
        return OGRLayer::GetFeatureCount(bForce);
255
0
    }
256
257
    OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
258
                      bool bForce) override
259
0
    {
260
0
        return m_srcLayer.GetExtent(iGeomField, psExtent, bForce);
261
0
    }
262
263
    OGRFeature *GetFeature(GIntBig nFID) override
264
0
    {
265
0
        auto poSrcFeature =
266
0
            std::unique_ptr<OGRFeature>(m_srcLayer.GetFeature(nFID));
267
0
        if (!poSrcFeature)
268
0
            return nullptr;
269
0
        return TranslateFeature(std::move(poSrcFeature)).release();
270
0
    }
271
272
    int TestCapability(const char *pszCap) const override
273
0
    {
274
0
        if (EQUAL(pszCap, OLCRandomRead) || EQUAL(pszCap, OLCCurveGeometries) ||
275
0
            EQUAL(pszCap, OLCMeasuredGeometries) ||
276
0
            EQUAL(pszCap, OLCZGeometries) ||
277
0
            (EQUAL(pszCap, OLCFastFeatureCount) && !m_poAttrQuery &&
278
0
             !m_poFilterGeom) ||
279
0
            EQUAL(pszCap, OLCFastGetExtent) || EQUAL(pszCap, OLCStringsAsUTF8))
280
0
        {
281
0
            return m_srcLayer.TestCapability(pszCap);
282
0
        }
283
0
        return false;
284
0
    }
285
};
286
287
}  // namespace
288
289
/************************************************************************/
290
/*                 GDALVectorSelectAlgorithm::RunStep()                 */
291
/************************************************************************/
292
293
bool GDALVectorSelectAlgorithm::RunStep(GDALPipelineStepRunContext &)
294
0
{
295
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
296
0
    CPLAssert(poSrcDS);
297
298
0
    CPLAssert(m_outputDataset.GetName().empty());
299
0
    CPLAssert(!m_outputDataset.GetDatasetRef());
300
301
0
    auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
302
303
0
    for (auto &&poSrcLayer : poSrcDS->GetLayers())
304
0
    {
305
0
        if (m_activeLayer.empty() ||
306
0
            m_activeLayer == poSrcLayer->GetDescription())
307
0
        {
308
0
            auto poLayer = std::make_unique<GDALVectorSelectAlgorithmLayer>(
309
0
                *poSrcLayer, m_outputLayerName);
310
0
            if (m_exclude)
311
0
            {
312
0
                poLayer->ExcludeFields(m_fields);
313
0
            }
314
0
            else
315
0
            {
316
0
                if (!poLayer->IncludeFields(m_fields, !m_ignoreMissingFields))
317
0
                    return false;
318
0
            }
319
0
            outDS->AddLayer(*poSrcLayer, std::move(poLayer));
320
0
        }
321
0
        else
322
0
        {
323
0
            outDS->AddLayer(
324
0
                *poSrcLayer,
325
0
                std::make_unique<GDALVectorPipelinePassthroughLayer>(
326
0
                    *poSrcLayer));
327
0
        }
328
0
    }
329
330
0
    m_outputDataset.Set(std::move(outDS));
331
332
0
    return true;
333
0
}
334
335
0
GDALVectorSelectAlgorithmStandalone::~GDALVectorSelectAlgorithmStandalone() =
336
    default;
337
338
//! @endcond