Skip to content

Commit

Permalink
Add 'gdal vector select' (extracting --fields functionality from 'gda…
Browse files Browse the repository at this point in the history
…l vector filter')
  • Loading branch information
rouault committed Feb 11, 2025
1 parent 7e7be15 commit 5a62208
Show file tree
Hide file tree
Showing 15 changed files with 613 additions and 349 deletions.
1 change: 1 addition & 0 deletions apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_library(
gdalalg_vector_read.cpp
gdalalg_vector_filter.cpp
gdalalg_vector_reproject.cpp
gdalalg_vector_select.cpp
gdalalg_vector_sql.cpp
gdalalg_vector_write.cpp
gdalinfo_lib.cpp
Expand Down
2 changes: 2 additions & 0 deletions apps/gdalalg_vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "gdalalg_vector_pipeline.h"
#include "gdalalg_vector_filter.h"
#include "gdalalg_vector_reproject.h"
#include "gdalalg_vector_select.h"
#include "gdalalg_vector_sql.h"

/************************************************************************/
Expand All @@ -44,6 +45,7 @@ class GDALVectorAlgorithm final : public GDALAlgorithm
RegisterSubAlgorithm<GDALVectorPipelineAlgorithm>();
RegisterSubAlgorithm<GDALVectorFilterAlgorithmStandalone>();
RegisterSubAlgorithm<GDALVectorReprojectAlgorithmStandalone>();
RegisterSubAlgorithm<GDALVectorSelectAlgorithmStandalone>();
RegisterSubAlgorithm<GDALVectorSQLAlgorithmStandalone>();
}

Expand Down
226 changes: 1 addition & 225 deletions apps/gdalalg_vector_filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,209 +40,8 @@ GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm(bool standaloneStep)
.SetReadFromFileAtSyntaxAllowed()
.SetMetaVar("<WHERE>|@<filename>")
.SetRemoveSQLCommentsEnabled();
AddArg("fields", 0, _("Selected fields"), &m_selectedFields);
}

namespace
{

/************************************************************************/
/* GDALVectorFilterAlgorithmLayer */
/************************************************************************/

class GDALVectorFilterAlgorithmLayer final
: public OGRLayer,
public OGRGetNextFeatureThroughRaw<GDALVectorFilterAlgorithmLayer>
{
private:
bool m_bIsOK = true;
OGRLayer *const m_poSrcLayer;
OGRFeatureDefn *const m_poFeatureDefn = nullptr;
std::vector<int> m_anMapSrcFieldsToDstFields{};
std::vector<int> m_anMapDstGeomFieldsToSrcGeomFields{};

CPL_DISALLOW_COPY_ASSIGN(GDALVectorFilterAlgorithmLayer)

std::unique_ptr<OGRFeature> TranslateFeature(OGRFeature *poSrcFeature) const
{
auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
poFeature->SetFID(poSrcFeature->GetFID());
const auto styleString = poSrcFeature->GetStyleString();
if (styleString)
poFeature->SetStyleString(styleString);
poFeature->SetFieldsFrom(
poSrcFeature, m_anMapSrcFieldsToDstFields.data(), false, false);
int iDstGeomField = 0;
for (int nSrcGeomField : m_anMapDstGeomFieldsToSrcGeomFields)
{
poFeature->SetGeomFieldDirectly(
iDstGeomField, poSrcFeature->StealGeometry(nSrcGeomField));
++iDstGeomField;
}
return poFeature;
}

DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(GDALVectorFilterAlgorithmLayer)

public:
GDALVectorFilterAlgorithmLayer(
OGRLayer *poSrcLayer, const std::vector<std::string> &selectedFields,
bool bStrict)
: m_poSrcLayer(poSrcLayer),
m_poFeatureDefn(new OGRFeatureDefn(poSrcLayer->GetName()))
{
SetDescription(poSrcLayer->GetDescription());
m_poFeatureDefn->SetGeomType(wkbNone);
m_poFeatureDefn->Reference();

std::set<std::string> oSetSelFields;
std::set<std::string> oSetSelFieldsUC;
for (const std::string &osFieldName : selectedFields)
{
oSetSelFields.insert(osFieldName);
oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
}

std::set<std::string> oSetUsedSetFieldsUC;

const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
for (int i = 0; i < poSrcLayerDefn->GetFieldCount(); ++i)
{
const auto poSrcFieldDefn = poSrcLayerDefn->GetFieldDefn(i);
auto oIter = oSetSelFieldsUC.find(
CPLString(poSrcFieldDefn->GetNameRef()).toupper());
if (oIter != oSetSelFieldsUC.end())
{
m_anMapSrcFieldsToDstFields.push_back(
m_poFeatureDefn->GetFieldCount());
OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
oSetUsedSetFieldsUC.insert(*oIter);
}
else
{
m_anMapSrcFieldsToDstFields.push_back(-1);
}
}

for (int i = 0; i < poSrcLayerDefn->GetGeomFieldCount(); ++i)
{
const auto poSrcFieldDefn = poSrcLayerDefn->GetGeomFieldDefn(i);
auto oIter = oSetSelFieldsUC.find(
CPLString(poSrcFieldDefn->GetNameRef()).toupper());
if (oIter != oSetSelFieldsUC.end())
{
m_anMapDstGeomFieldsToSrcGeomFields.push_back(i);
OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
oSetUsedSetFieldsUC.insert(*oIter);
}
}

auto oIter = oSetSelFieldsUC.find(
CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper());
if (m_poFeatureDefn->GetGeomFieldCount() == 0 &&
oIter != oSetSelFieldsUC.end() &&
poSrcLayerDefn->GetGeomFieldCount() == 1)
{
const auto poSrcFieldDefn = poSrcLayerDefn->GetGeomFieldDefn(0);
m_anMapDstGeomFieldsToSrcGeomFields.push_back(0);
OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
oSetUsedSetFieldsUC.insert(*oIter);
}

if (oSetUsedSetFieldsUC.size() != oSetSelFields.size())
{
for (const std::string &osName : oSetSelFields)
{
if (!cpl::contains(oSetUsedSetFieldsUC,
CPLString(osName).toupper()))
{
CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_AppDefined,
"Field '%s' does not exist in layer '%s'.%s",
osName.c_str(), poSrcLayer->GetDescription(),
bStrict ? "" : " It will be ignored");
if (bStrict)
m_bIsOK = false;
}
}
}
}

~GDALVectorFilterAlgorithmLayer() override
{
if (m_poFeatureDefn)
m_poFeatureDefn->Dereference();
}

bool IsOK() const
{
return m_bIsOK;
}

OGRFeatureDefn *GetLayerDefn() override
{
return m_poFeatureDefn;
}

GIntBig GetFeatureCount(int bForce) override
{
if (!m_poAttrQuery && !m_poFilterGeom)
return m_poSrcLayer->GetFeatureCount(bForce);
return OGRLayer::GetFeatureCount(bForce);
}

OGRErr GetExtent(OGREnvelope *psExtent, int bForce) override
{
return m_poSrcLayer->GetExtent(psExtent, bForce);
}

OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override
{
return m_poSrcLayer->GetExtent(iGeomField, psExtent, bForce);
}

void ResetReading() override
{
m_poSrcLayer->ResetReading();
}

OGRFeature *GetNextRawFeature()
{
auto poSrcFeature =
std::unique_ptr<OGRFeature>(m_poSrcLayer->GetNextFeature());
if (!poSrcFeature)
return nullptr;
return TranslateFeature(poSrcFeature.get()).release();
}

OGRFeature *GetFeature(GIntBig nFID) override
{
auto poSrcFeature =
std::unique_ptr<OGRFeature>(m_poSrcLayer->GetFeature(nFID));
if (!poSrcFeature)
return nullptr;
return TranslateFeature(poSrcFeature.get()).release();
}

int TestCapability(const char *pszCap) override
{
if (EQUAL(pszCap, OLCRandomRead) || EQUAL(pszCap, OLCCurveGeometries) ||
EQUAL(pszCap, OLCMeasuredGeometries) ||
EQUAL(pszCap, OLCZGeometries) ||
(EQUAL(pszCap, OLCFastFeatureCount) && !m_poAttrQuery &&
!m_poFilterGeom) ||
EQUAL(pszCap, OLCFastGetExtent) || EQUAL(pszCap, OLCStringsAsUTF8))
{
return m_poSrcLayer->TestCapability(pszCap);
}
return false;
}
};

} // namespace

/************************************************************************/
/* GDALVectorFilterAlgorithm::RunStep() */
/************************************************************************/
Expand Down Expand Up @@ -284,30 +83,7 @@ bool GDALVectorFilterAlgorithm::RunStep(GDALProgressFunc, void *)
}
}

if (ret && !m_selectedFields.empty())
{
auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>();
outDS->SetDescription(poSrcDS->GetDescription());

for (int i = 0; i < nLayerCount; ++i)
{
auto poSrcLayer = poSrcDS->GetLayer(i);
ret = ret && (poSrcLayer != nullptr);
if (ret)
{
auto poLayer = std::make_unique<GDALVectorFilterAlgorithmLayer>(
poSrcLayer, m_selectedFields, /* bStrict = */ true);
ret = poLayer->IsOK();
if (ret)
{
outDS->AddLayer(std::move(poLayer));
}
}
}

m_outputDataset.Set(std::move(outDS));
}
else if (ret)
if (ret)
{
m_outputDataset.Set(m_inputDataset.GetDatasetRef());
}
Expand Down
4 changes: 1 addition & 3 deletions apps/gdalalg_vector_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ class GDALVectorFilterAlgorithm /* non final */
public:
static constexpr const char *NAME = "filter";
static constexpr const char *DESCRIPTION = "Filter a vector dataset.";
static constexpr const char *HELP_URL =
"/programs/gdal_vector_pipeline.html";
static constexpr const char *HELP_URL = "/programs/gdal_vector_filter.html";

static std::vector<std::string> GetAliases()
{
Expand All @@ -42,7 +41,6 @@ class GDALVectorFilterAlgorithm /* non final */

std::vector<double> m_bbox{};
std::string m_where{};
std::vector<std::string> m_selectedFields{};
};

/************************************************************************/
Expand Down
2 changes: 2 additions & 0 deletions apps/gdalalg_vector_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "gdalalg_vector_clip.h"
#include "gdalalg_vector_filter.h"
#include "gdalalg_vector_reproject.h"
#include "gdalalg_vector_select.h"
#include "gdalalg_vector_sql.h"
#include "gdalalg_vector_write.h"

Expand Down Expand Up @@ -193,6 +194,7 @@ GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()
m_stepRegistry.Register<GDALVectorClipAlgorithm>();
m_stepRegistry.Register<GDALVectorReprojectAlgorithm>();
m_stepRegistry.Register<GDALVectorFilterAlgorithm>();
m_stepRegistry.Register<GDALVectorSelectAlgorithm>();
m_stepRegistry.Register<GDALVectorSQLAlgorithm>();
}

Expand Down
Loading

0 comments on commit 5a62208

Please sign in to comment.